/**
 * Copyright (c) suzuki ryoutoku
 * See this code regarding the Apache License Version 2.0
 * @file Graphics.cpp
 * @author r-suzuki
 */

//=============================================================================
//	pre processor
//=============================================================================
#include <new>
#include "Graphics.h"
#include <cmath>
#include <iomanip>
#include <cstdlib>
using namespace library::graphics;


//=============================================================================
//	Define RenderingManager's method
//=============================================================================
/**
 * unique constructor.
 * \note
 * Set opengl's context for display pointer that is specified by argument.
 * @param arg Display: x window sytems's pointer
 * @param windowid
 * @param arg3
 *
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2007-05-21
 */
RenderingManager::RenderingManager(LogManager* arg3)
{
  // set window width & height
  this->m_window_width = 0;
  this->m_window_height = 0;


  // To create screen
  RECT tmp = { 10, 10, 300, 350};
  Screen *screen = new Screen(tmp, library::graphics::Screen::PERSPECTIVE);
  screen->setM_rm(this);
  this->m_screen.push_back(screen);

  // Next code is initialize a member m_idm.
  this->_idm = ImageDataManager::getInstance();
}


/**
 * destructor
 * @author suzuki ryoutoku
 * @date 2007-6-2
 * @version 1.0
 */
RenderingManager::~RenderingManager()
{
  ::glDeleteLists( this->m_font_number, 128 );
#ifdef DEBUG
  cout << "RenderingManager's destructor" << endl;
#endif
  vector<Screen*>::iterator ite = this->m_screen.begin();
  while( ite != this->m_screen.end() ){
	 delete (*ite);
	 ite++;
  }
  this->m_screen.clear();
}

/**
 * To execute drawing 3d
 * @author suzuki ryoutoku
 * @date 2007-5-22
 * @version 1.0
 */
void RenderingManager::draw(void)
{
  ::glRenderMode(GL_RENDER);

  // Enable Depth Buffer
  ::glEnable(GL_DEPTH_TEST);

  // To raise accuracy in gl
  ::glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
  ::glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

  // To select flat shading
  ::glShadeModel(GL_FLAT);

  // I set initialized color is sky blue.
  ::glClearColor(0.6, 0.6, 1.0, 0);
  ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

  // To select clockwise for face connectivity
  ::glFrontFace(GL_CCW); // It's default

  // To set culling face
  ::glEnable(GL_CULL_FACE);
  ::glCullFace(GL_BACK);

  ::glEnable(GL_NORMALIZE);


  for( vector<Screen*>::iterator ite = this->m_screen.begin();
		ite != this->m_screen.end();
		ite++ )
	 {
	   (*ite)->draw();
	 }
  ::glFlush();


}

/**
 * To resize window
 *
 * @param width window's width
 * @param height window's height
 *
 * @author suzuki ryoutoku
 * @date 2007-8-14
 * @version 1.0
 */
void RenderingManager::resize(int width, int height)
{
  RECT rect;
  rect.top = 0;
  rect.left = 0;
  rect.bottom = height;
  rect.right= width;
  m_screen[0]->setM_rect(rect);
  m_window_width = width;
  m_window_height = height;
}


/**
 * To search selecting polygon by mouse picking.
 * \note
 *
 * @param mouse mouse's coordinate
 * @param model target data
 * @param screen If it's NULL in default, then target screen is m_screen[0].
 *
 * @return polygon global index. when it is negative, failure occurs.
 * @retval -2 no polygon
 *
 * @author suzuki ryoutoku
 * @date 2007-12-22
 * @version 1.0
 */
int RenderingManager::selection(const GraphicalObjectType& gotype,
								POINT mouse, 
								Model* model,
								Screen* screen)
{
  // search screen in which argument model.
  Screen* target = screen;
  if( target == NULL ){
	target = this->m_screen[0];
  }

  // allocate selection buffer
  GLuint* selection=NULL;
  try{
	switch( gotype ){
	case library::graphics::POLYGON:
	  selection = new GLuint[model->get_polygon_sum()+4];
	  ::glSelectBuffer(model->get_polygon_sum()+4, selection);
	  
	  break;
	case library::graphics::VERTEX:
	  selection = new GLuint[model->get_vertex_sum()+4];
	  ::glSelectBuffer(model->get_vertex_sum()+4, selection);
	  break;
	}
  }catch( bad_alloc ){
#ifdef DEBUG
	cout << "can not allocate buffer" << endl;
#endif
	this->m_log_manager->print("can not allocate buffer\n");
	return 0;
  }
  
  
  // check selecting poygon
  ::glRenderMode(GL_SELECT);

  ::glEnable(GL_DEPTH_TEST);
  ::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POINT_BIT);

  ::glFrontFace(GL_CCW);
  ::glCullFace(GL_BACK);

  ::glInitNames();
#if 0
  switch( gotype ){
  case POLYGON:
	::glPushName(GL_FILL);
  break;
  case VERTEX:
	::glPushName(GL_POINT);
  break;
  }
#else
  ::glPushName(-1);
#endif

  target->selection(gotype, mouse, model);

  GLint hits = ::glRenderMode(GL_RENDER);

  if( hits <= 0 ){
	delete [] selection;
	return -2;
  }
  
  int retval = selection[3];//this is interim.
  double min_near = (double)selection[1]/(double)0x7fffffff;
  // To search most near polygon
  for( int i = 0; i < hits; i ++){
	unsigned int n = selection[i*4 + 0];
	double near = (double)selection[i*4 + 1] / (double)0x7fffffff;
	double far  = (double)selection[i*4 + 2] / (double)0x7fffffff;
	int select_index = selection[i*4 + 3];// most near polygon
	if( min_near > near ){
	  retval = select_index;
	}
  }

  delete [] selection;
  return retval;
}

//=============================================================================
//	define Screen's method 
//=============================================================================
/**
 * constructor
 *
 * @param location substitute (Screen::m_rect)
 * @param type (Screen::PERSPECTIVE) in default, substitute (Screen::m_type)
 *
 * @author suzuki ryoutoku
 * @date 2007-8-28
 * @version 1.0
 */
library::graphics::Screen::Screen(const RECT& location,
								  unsigned int type)
{
  this->m_rect = location;
  this->m_type = type;
  this->m_rm = NULL;
  this->m_camera = NULL;
  this->m_drawcommands = new MacroCommand();
  this->m_camera = new Camera();
  this->m_lights.push_back(new Light(0) );
  this->m_lights[0]->setM_state(true);
}


/**
 * @author suzuki ryoutoku
 * @date 2007-8-28
 * @version 1.0
 */
library::graphics::Screen::~Screen()
{
  if( NULL != this->m_camera ){
	delete this->m_camera;
  }

  if( NULL != this->m_drawcommands ){
	delete this->m_drawcommands;
  }

  vector<Light*>::iterator ite = this->m_lights.begin();
  while( ite != this->m_lights.end() ){
	delete (*ite);
	ite++;
  }
  this->m_lights.clear();
}

/**
 * Drawing screen.
 * \note
 * First process is filling background (color is white).
 *
 * Second process is calling (Camera::setupCamera) of 
 * (Screen::m_camera)'s method.
 *
 * Third process is calling (MacroCommand::execute) of 
 * (Screen::m_drawcommands)'s method for (Screen::m_rect).
 *
 * @author suzuki ryoutoku
 * @date 2007-8-28
 * @version 1.0
 */
void library::graphics::Screen::draw(void)
{
  // setting viewport for drawing background
  ::glViewport( this->m_rect.left, 
				this->m_rect.top, 
				this->m_rect.right, 
				this->m_rect.bottom);

  // second process
  // setting viewport for drawing 3d
  ::glMatrixMode( GL_PROJECTION );
  ::glLoadIdentity();
  ::glViewport( this->m_rect.left, 
				this->m_rect.top, 
				this->m_rect.right, 
				this->m_rect.bottom);
  this->m_camera->setupCamera(*this);

  // setting light
  ::glMatrixMode(GL_MODELVIEW);// coordinate of light is not local, is global
  ::glLoadIdentity();
  if( glIsEnabled(GL_LIGHTING) == GL_FALSE ){
	::glEnable(GL_LIGHTING);
  }

  for( size_t i = 0; i < this->m_lights.size(); i++){
	this->m_lights[i]->enable();
  }

  // third process
  this->m_drawcommands->execute(this);
  

  // end process
  ::glMatrixMode(GL_PROJECTION);
  ::glLoadIdentity();
}


/**
 * To regist Graphical Command.
 *
 * @param arg insert (Screen::m_drawcommands)
 *
 * @author suzuki ryoutoku
 * @date 2007-9-20
 * @version 1.0
 */
bool library::graphics::Screen::registGraphicalCommand(GraphicalCommand* arg)
{
#ifdef DEBUG
  cout << "CommandType = ";
  switch( arg->getM_type() ){
  case GraphicalCommand::TESTCOMMAND:
	cout << "TestCommand" << endl;
	break;
  case GraphicalCommand::MACROCOMMAND:
	cout << "MacroCommand" << endl;
	break;
  case GraphicalCommand::SPRITE:
	cout << "Sprite" << endl;
	break;
  case GraphicalCommand::DRAWBOX:
	cout << "DrawBox" << endl;
	break;
  case GraphicalCommand::MODEL:
	cout << "Model" << endl;
	break;
  case GraphicalCommand::DRAWSTRING:
	cout << "DrawString" << endl;
	break;
  case GraphicalCommand::DRAWPOLYGONS:
	cout << "DrawPolgons" << endl;
	break;
  default:
	cout << "UnKnown" << endl;
  }
#endif

  arg->assignTargetRenderingManager( this->m_rm );
  this->m_drawcommands->append( arg );
  return true;
}

/**
 * To remove Graphical Command
 *
 * @param arg 
 *
 * @author suzuki ryoutoku 
 * @date 2007-10-14
 * @version 1.0
 */
bool library::graphics::Screen::cancelGraphicalCommand(GraphicalCommand* arg)
{
  if( arg == NULL ){
	return false;
  }
  return this->m_drawcommands->cancel( arg );
}

/**
 *
 * \note
 *
 *
 * @author suzuki ryoutoku
 * @date 2007-12-22
 * @version 1.0
 */
int library::graphics::Screen::selection(const GraphicalObjectType& gotype,
										 POINT mouse, 
										 Model* model)
{
  // To get current view port
  ::glMatrixMode(GL_PROJECTION);
  ::glLoadIdentity();
  ::glViewport(this->getM_rect()->left,
			   this->getM_rect()->top,
			   this->getM_rect()->right,
			   this->getM_rect()->bottom);
  GLint vp[4];
  ::glGetIntegerv(GL_VIEWPORT, vp);
  ::glPopMatrix();


  // create projection matrix for selection
  ::glMatrixMode(GL_PROJECTION);
  ::glLoadIdentity();

  float width;
  float height;

  switch( gotype ){
	case library::graphics::POLYGON:
	  width=height=1.0f;
	  break;
  case library::graphics::VERTEX:
	width = height = 10.0f;
	  break;
  }
  /* 
	 2*vp[1] of second argument express blank space in 3d drawing area.
	 Mouse coordinate 's origin is upper left. 
	 OpenGL coordinate's origin is left below.
	 Therefore, subtract 2 times blank space from mouse's y coordinate.
  */ 
  this->createPickingViewport((float)(mouse.x),
							  (float)(((vp[3]) - (mouse.y-2*vp[1]) ) ),
							  width, // to set width
							  height, // to set height
							  vp); // viewport
  // create perspective matix
  this->m_camera->setupCamera(*this);


  switch( gotype ){
  case library::graphics::POLYGON:
	model->selectionPolygon();
	break;
  case library::graphics::VERTEX:
	model->selectionVertex();
	break;
  }

  ::glMatrixMode(GL_PROJECTION);
  ::glPopMatrix();
  return 0;
}


/**
 * To create picking viewport.
 * \note
 *
 *
 * @author suzuki ryoutoku
 * @date 2007-11-14
 * @version 1.0
 */
void library::graphics::Screen::createPickingViewport(float x, 
													  float y, 
													  float width, 
													  float height,
													  int viewport[4])
{
  float sx, sy;
  float tx, ty;
  ::glTranslatef((viewport[2] - 2.0f * (x - viewport[0])) / width,
				 (viewport[3] - 2.0f * (y - viewport[1])) / height,
				 0.0);
  ::glScalef(viewport[2] / width, viewport[3] / height, 1.0);
}

//=============================================================================
//	Define Camera's method
//=============================================================================
/**
 * @author suzuki ryoutoku 
 * @date 2007-9-1
 * @version 1.0
 */
Camera::Camera()
{
#ifdef DEBUG
  cout <<"create camera" << endl;
#endif
  this->m_angle = M_PI/4.0;//45°
  this->m_front = 0.1;
  this->m_back = 20.0;
  this->m_aspect = 0;
  this->m_view_position = Vector<double>(0.0, 0.0, 5.0, 1.0);// after computing
  this->m_focus_position = Vector<double>(0.0, 0.0, 0.0, 0.0);
  this->m_up_direction = Vector<double>(0.0, 1.0, 0.0, 1.0);
}

/**
 * @author suzuki ryoutoku
 * @date 2007-9-2
 * @version 1.0
 */
Camera::~Camera()
{
#ifdef DEBUG
  cout <<"destroy camera" << endl;
#endif
}


/**
 * To set up camera 
 *
 * @param arg is target screen
 * @author suzuki ryoutoku 
 * @date 2007-9-1
 * @version 1.0
 */
void Camera::setupCamera(library::graphics::Screen& arg)
{
  float width = (float)(arg.getWidth());
  float height = (float)(arg.getHeight());
  this->m_aspect = width/height;

  switch( arg.getM_type() ){
  case library::graphics::Screen::NONE:
#ifdef DEBUG
	cout << "error" << endl;
#endif
	return;
  case library::graphics::Screen::TWO_DIMENSION:
	{
	  ::glOrtho( 0.0,
				 (GLdouble)(width),
				 0.0,
				 (GLdouble)(height),
				 -1.0,
				 1.0);
	  
	}
  case library::graphics::Screen::PERSPECTIVE:
	{
	  // Instead of gluPerspective process
	  Matrix<double> mat;
	  // tan() is divergent in this situation, Fix this at a later date.
	  double f = 1.0 / tan(this->m_angle/2.0);
	  mat.m00=f / this->m_aspect;
	  mat.m05=f;
	  mat.m10=(this->m_back+this->m_front)/(this->m_front-this->m_back);
	  mat.m11=-1.0;
	  mat.m14=(2.0*this->m_back*this->m_front)/(this->m_front-this->m_back);
	  mat.m15=0.0;
	  ::glMultMatrixd((double*)(mat.m));

	  // Instead of gluLookAt process
	  //::glMatrixMode( GL_MODELVIEW );
	  //::glPushMatrix();
	  //::glLoadIdentity();
	  Vector<double> F = this->m_focus_position - this->m_view_position;
	  F.normalizing();
	  Vector<double> s = F.outerProduct(this->m_up_direction);
	  Vector<double> u = s.outerProduct(F);
	  Matrix<double> look_mat;
	  look_mat.m00=s.x;      look_mat.m04=s.y;      look_mat.m08=s.z;
	  look_mat.m01=u.x;      look_mat.m05=u.y;      look_mat.m09=u.z;
	  look_mat.m02=-1.0*F.x; look_mat.m06=-1.0*F.y; look_mat.m10=-1.0*F.z;


	  ::glMultMatrixd((double*)(look_mat.m));
	  ::glTranslated(-this->m_view_position.x,
					 -this->m_view_position.y,
					 -this->m_view_position.z);
	}
  break;
  }
}

/**
 * This method allow view postion to move fitting model data.
 * \note
 * This method's aim is to place reading model data on center in viewfrustum.
 * Algorism is simple, 
 * First process is computing AABB of model data, 
 *
 * Second is computing two view position's z coordinate from world origin 
 * that inverse tangent of specified angle is multiplied by each edge of AABB.
 *
 * Two view position's z coordinate, one is from AABB's width, other is form 
 * AABB's height.
 *
 * Thrid process is comparing z coordinate from width of AABB to z coordinate 
 * from heigth of AABB and selecting most length.
 * 
 * Fourth process is adding a half length of AABB's depth to selecting z 
 * coodinate.
 *
 * Fifth process is to assign selecting z coodinate viewfrustum's far to a 
 * half length of AABB's depth.
 *
 * @param arg model data
 *
 * @author suzuki ryoutoku 
 * @date 2007-12-31
 * @version 1.0
 */
bool Camera::moveToFitModel(Model* arg)
{
  // computing width ,height and depth of model data
  double width;
  double height;
  double depth;
  arg->computeSize(&width, &height, &depth);
  cout << "width = " << width 
	   << " height = " << height 
	   << " depth = " << depth << endl;
  
  width = width / 2.0;
  height = height / 2.0;

  double view_position_width_z = width/tan(this->m_angle/2.0);
  double view_position_height_z = height/tan(this->m_angle/2.0)/this->m_aspect;

  if(view_position_height_z > view_position_width_z ){
	this->m_view_position.z = view_position_height_z + depth/2;
	this->m_back = view_position_height_z + depth*2;
  }else{
	this->m_view_position.z = view_position_width_z + depth/2;
	this->m_back = view_position_width_z + depth*2;
  }
}

//=============================================================================
//	Define Light's method
//=============================================================================
/**
 * \note
 *
 * @param index light name( Please no specify parameter over 8)
 * @param iposition (0, 0, 1, 0) in default
 * @param iambient (1, 1, 1, 1) in default
 * @param idiffuse (1, 1, 1, 1) in default
 * @param ispecular (1, 1, 1, 1) in default
 *
 * @author suzuki ryoutoku
 * @date 2007-10-3
 * @version 1.0
 */
Light::Light(unsigned int index, 
			 Vector<float> iposition, 
			 Color<float> iambient, 
			 Color<float> idiffuse, 
			 Color<float> ispecular)
{
  this->m_state = false;
  iposition.normalizing();
  this->m_position = iposition;
  this->m_ambient = iambient;
  this->m_diffuse = idiffuse;
  this->m_specular = ispecular;
  this->m_lightkind = DISTANT;// light's kind is parallel in default
  //this->m_lightkind = POINTING;
  this->m_constant = 2.0f;
  this->m_linear = 0.5f;
  this->m_quadratic = 0.0f;
  this->m_direction = Vector<float>(0.0, 0.0, 1.0, 0.0);
  this->m_cutoff = 15.0f;
  this->m_exponent = 10.0f;
  this->m_lightname = 0x0000;
  
  this->m_lightname = GL_LIGHT0; // over 8
  switch( index ){
  case 0:
	this->m_lightname = GL_LIGHT0;
	break;
  case 1:
	this->m_lightname = GL_LIGHT1;
	break;
  case 2:
	this->m_lightname = GL_LIGHT2;
	break;
  case 3:
	this->m_lightname = GL_LIGHT3;
	break;
  case 4:
	this->m_lightname = GL_LIGHT4;
	break;
  case 5:
	this->m_lightname = GL_LIGHT5;
	break;
  case 6:
	this->m_lightname = GL_LIGHT6;
	break;
  case 7:
	this->m_lightname = GL_LIGHT7;
	break;
  }
}

/**
 * enable light
 * @author suzuki ryoutoku
 * @date 2007-10-3
 * @version 1.0
 */
void Light::enable(void)
{
  if( !this->m_state ){
	glDisable( this->m_lightname );
	return;
  }
    
  // enable light
  if( glIsEnabled(GL_LIGHTING) == GL_FALSE ){
	glEnable(GL_LIGHTING);
  }
  // setting common parameter of light
  ::glEnable(this->m_lightname);
  ::glLightfv(this->m_lightname, GL_DIFFUSE, this->m_diffuse.color);
  ::glLightfv(this->m_lightname, GL_SPECULAR, this->m_specular.color);
  ::glLightfv(this->m_lightname, GL_AMBIENT, this->m_ambient.color);
  if( this->m_lightkind != DISTANT ){
	this->m_position.w = 1.0f;
	::glLightfv(this->m_lightname, GL_POSITION, this->m_position.vec);
  }else{
	this->m_position.w = 0.0f;
	::glLightfv(this->m_lightname, GL_POSITION, this->m_position.vec);
  }

  // setting indigenous param
  switch( this->m_lightkind ){
  case SPOT:
	{
	  ::glLightfv(this->m_lightname,GL_SPOT_DIRECTION, this->m_direction.vec);
	  ::glLightf(this->m_lightname,GL_SPOT_CUTOFF, this->m_cutoff);
	  ::glLightf(this->m_lightname,GL_SPOT_EXPONENT, this->m_exponent);
	  ::glLightf(this->m_lightname,GL_CONSTANT_ATTENUATION, this->m_constant);
	  ::glLightf(this->m_lightname,GL_LINEAR_ATTENUATION, this->m_linear);
	  ::glLightf(this->m_lightname,GL_QUADRATIC_ATTENUATION,this->m_quadratic);
	}
	break;
  case POINTING:
	{
	  // when specify 180, stop spot light
	  ::glLightf(this->m_lightname,GL_SPOT_CUTOFF, 180.0f);
	  ::glLightf(this->m_lightname,GL_CONSTANT_ATTENUATION,this->m_constant);
	  ::glLightf(this->m_lightname,GL_LINEAR_ATTENUATION,this->m_linear);
	  ::glLightf(this->m_lightname,GL_QUADRATIC_ATTENUATION,this->m_quadratic);
	}
	break;
  default:
	return;
  }
}

//=============================================================================
//	Define GraphicalCommand's method
//=============================================================================
/**
 * @version 1.0
 * @author suzuki ryoutoku
 * @date 2007-6-3
 */
GraphicalCommand::GraphicalCommand(CommandType arg) :
  m_type(arg) 
{
  this->m_target_rm = NULL;
  this->m_priority = 1;
  this->m_state = 0;
}


/**
 * virtual function
 * @author suzuki ryoutoku
 * @date 2007-6-4
 * @version 1.0
 */
GraphicalCommand::~GraphicalCommand()
{
}


/**
 * (Screen::registGraphicalCommand)
 * \note
 * If you want to equip special process, please overide this method.
 * @author suzuki ryoutoku
 * @date 2007-6-4
 * @version 1.0
 */
void GraphicalCommand::assignTargetRenderingManager(RenderingManager* arg)
{
  this->m_target_rm = arg;
}

//=============================================================================
//	Define MacroCommand's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2007-6-4
 * @version 1.0
 */
MacroCommand::MacroCommand(GraphicalCommand::CommandType arg) :
  GraphicalCommand(arg)
{
}


/**
 * \note 
 * This method do not release list which (Macrocommand::m_commands) 
 * have some pointers.
 * No determining whether it's the instance or the allocating memory.
 * @author suzuki ryoutoku
 * @version 1.1
 * @date 2007-6-4 new create
 * @date 2007-12-22 To fix invalid to release memory.
 */
MacroCommand::~MacroCommand()
{
#if DEBUG
  cout << "MacroCommand's destructor" << endl;
#endif
  this->m_commands.clear();
  
}


/**
 *
 * @param screen is target
 *
 * @author suzuki ryoutoku
 * @date 2007-6-4
 * @version 1.0
 */
int MacroCommand::execute(Screen* screen)
{
  list<GraphicalCommand*>::iterator ite = this->m_commands.begin();
  while( ite != this->m_commands.end() ){
	(*ite)->execute(screen);
	ite++;
  }
  
  return 0;
}


/**
 * \note
 *
 * @return -1 error
 * @author suzuki ryoutoku
 * @date 2007-6-4
 * @version 1.0
 */
int MacroCommand::append(GraphicalCommand* arg)
{
  if( arg->GraphicalCommand::getM_type() == NONE ){
	return -1;
  }
  if( arg->GraphicalCommand::getM_priority() == 0 ){
	this->m_commands.push_front(arg);
  }else{
	// If registed command is heighter priority, command order is last.
	this->m_commands.push_back(arg);
  }
  return 0;

}

/**
 * \note
 *
 *
 * @author suzuki ryoutoku 
 * @date 2007-10-14
 * @version 1.0
 */
bool MacroCommand::cancel(GraphicalCommand* arg)
{
  list<GraphicalCommand*>::iterator ite = this->m_commands.begin();
  while( ite != this->m_commands.end() ){
	if( arg == *ite ){
	  this->m_commands.erase( ite );
	  return true;
	}
	ite++;
  }
  return false;
}
//=============================================================================
//	Define Sprite's method
//=============================================================================
/**
 * \note
 * set white to #m_color
 * @param filepass NULL in default
 * @author suzuki ryoutoku
 * @date 2007-6-4
 * @version 1.0
 */
Sprite::Sprite(GraphicalCommand::CommandType arg) :
  GraphicalCommand(arg)
{
  this->GraphicalCommand::setM_priority( 0 );

  this->m_color.r = 1.0;
  this->m_color.g = 1.0;
  this->m_color.b = 1.0;
  this->m_color.a = 1.0;

  this->m_rect.top = 0;
  this->m_rect.left = 0;
  this->m_rect.right = 0;
  this->m_rect.bottom = 0;

  this->m_texid = 0xFFFFFFFF;
  this->m_uv[0] = Vector2D<float>(0.0f, 0.0f);
  this->m_uv[1] = Vector2D<float>(1.0f, 0.0f);
  this->m_uv[2] = Vector2D<float>(1.0f, 1.0f);
  this->m_uv[3] = Vector2D<float>(0.0f, 1.0f);
}

/**
 * @author suzuki ryoutoku
 * @date 2007-6-4
 * @version 1.0
 */
Sprite::~Sprite()
{
}


/**
 * @param screen target
 * @version 1.0
 * @author suzuki ryoutoku
 * @date 2007-06-04
 */
int Sprite::execute(Screen* screen)
{
  GLint vp[4];
  if( this->GraphicalCommand::getM_state() == 1 ) return 0;

  // set polygon mode
  ::glEnable( GL_POLYGON_OFFSET_FILL );
  ::glPolygonOffset( 0.5, 0.5 );
  ::glPolygonMode( GL_FRONT, GL_FILL );

  // set texture for open gl
  if( this->m_texid != 0xFFFFFFFF ){
	::glEnable(GL_TEXTURE_2D);
	::glBindTexture(GL_TEXTURE_2D , this->m_texid);
	::glEnable(GL_BLEND);
	::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  }

  
  // set screen coordinate in 2d
  if( screen->getM_type() != Screen::TWO_DIMENSION ){
	// acquire viewport
	::glGetIntegerv(GL_VIEWPORT, vp);
	// set projection
	::glMatrixMode(GL_PROJECTION);
	::glPushMatrix(); // stack matrix
	::glLoadIdentity();
	::glViewport( (GLint)screen->getM_rect()->left, 
				  (GLint)screen->getM_rect()->top, 
				  (GLint)screen->getM_rect()->right, 
				  (GLint)screen->getM_rect()->bottom);
	GLdouble width 
	  = screen->getM_rect()->right - screen->getM_rect()->left;
	GLdouble height 
	  = screen->getM_rect()->bottom - screen->getM_rect()->top;
	::glOrtho( 0.0, 
			   width, 
			   0.0, 
			   height,
			   -1.0,
			   1.0);
  }

  // setting my coordinate
  ::glMatrixMode(GL_MODELVIEW);
  ::glPushMatrix();
  ::glLoadIdentity();
  this->getM_coordinate()->settingOpenGL();
    
  // disable lighting
  ::glDisable( GL_LIGHTING );
  
  // enable transparent
  ::glAlphaFunc(GL_GREATER, 0.5);// when alpha less than 0xFF>>1
  ::glEnable(GL_ALPHA_TEST); 

  // if you want semi transparency, set a to 0.6, 0.5, 0.4...
  ::glColor4fv(this->m_color.color);

  // orign's y coordinate is top, x coordinate is left
  ::glBegin(GL_QUADS);
  {
 	::glTexCoord2f(this->m_uv[0].u, this->m_uv[0].v);
 	::glVertex2d(0.0,
 				 0.0);
 	
 	::glTexCoord2f(this->m_uv[1].u, this->m_uv[1].v);
 	::glVertex2d(this->m_rect.right - m_rect.left,
 				 0.0);
 	
 	::glTexCoord2f(this->m_uv[2].u, this->m_uv[2].v);
 	::glVertex2d(this->m_rect.right - this->m_rect.left,
 				 this->m_rect.bottom - m_rect.top);
 
 	
 	::glTexCoord2f(this->m_uv[3].u, this->m_uv[3].v);
 	::glVertex2d(0.0,
 				 this->m_rect.bottom - m_rect.top);
  }
  ::glEnd();

  ::glEnable( GL_LIGHTING);
  if( this->m_texid != 0xFFFFFFFF ){
	::glDisable(GL_BLEND);
	::glDisable(GL_ALPHA_TEST);
	::glDisable(GL_TEXTURE_2D);
  }

  // pull out matrix
  if( screen->getM_type() != Screen::TWO_DIMENSION ){
	::glMatrixMode( GL_PROJECTION );
	::glPopMatrix();
	
	// reconstruct viewport
	::glViewport(vp[0], vp[1], vp[2], vp[3]);
  }

  // enable lighting
  ::glEnable( GL_LIGHTING );
  // disable testing alpha
  ::glDisable(GL_ALPHA_TEST); 
  // cancel depth buffer
  ::glClear( GL_DEPTH_BUFFER_BIT );

  ::glMatrixMode(GL_MODELVIEW);
  ::glPopMatrix();
  
  return 0;
}


/**
 * set region of sprite
 * @param ileft x coordinate of orign of sprite
 * @param itop y coordinate of orign of sprite
 * @param iright x coordinate of terminal point of sprite
 * @param ibottom y coordinate of terminal point of sprite
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2007-06-05
 */
void Sprite::setM_rect(int ileft, int ibottom, int iright, int itop)
{
  if( ileft > 0 ){
	this->m_rect.left = ileft;
	getM_coordinate()->getM_pivot()->x = ileft;
  }
  if( itop > 0 ){
	this->m_rect.top = itop;
	getM_coordinate()->getM_pivot()->y = itop;
  }

  if( iright ){
	this->m_rect.right = iright;
  }

  if( ibottom > 0 ){
	this->m_rect.bottom = ibottom;
  }
}

/**
 * when you set (0,0), left upper screen 
 * \note
 * Screen's orign (0,0) in 2d projection, 
 *
 * @param ileft orign's x coordinate
 * @param itop orign's y coordinate
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2007-06-05
 */
void Sprite::setPoint( int ileft, int itop)
{
  this->m_rect.left = ileft;
  this->m_rect.top = itop;
}


/**
 * Whether eval arg in or out region of sprite
 * @param arg 
 * @retval true arg in region of sprite
 * @retval false arg out region of sprite
 * @version 1.0
 * @author suzuki ryoutoku
 * @date 2007-06-05
 */
bool Sprite::insideSprite( POINT arg )
{
  if( this->m_rect.left <= arg.x 
	  && arg.x <= this->m_rect.right ){
	if( this->m_rect.top <= arg.y ){
	  if( arg.y <= this->m_rect.bottom ){
		return true;
	  }
	}
  }
  return false;
}

/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-3
 */
void Sprite::setTextureImage(ImageData* image)
{
  this->m_texid = image->getM_texid();
  float mh = image->getM_memory_height();
  float mw = image->getM_memory_width();
  float h = image->getM_height();
  float w = image->getM_width();
  this->m_uv[1] = Vector2D<float>(w/mw, 0.0f);
  this->m_uv[2] = Vector2D<float>(w/mw, h/mh);
  this->m_uv[3] = Vector2D<float>(0.0f, h/mh);
}

/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-7-28
 */
void Sprite::setM_uv(const Vector2D<float>& arg1,
					 const Vector2D<float>& arg2,
					 const Vector2D<float>& arg3,
					 const Vector2D<float>& arg4)
{
  this->m_uv[0] = arg1;
  this->m_uv[1] = arg2;
  this->m_uv[2] = arg3;
  this->m_uv[3] = arg4;
}

//=============================================================================
//	Define's ImageData method
//=============================================================================
/**
 * @param name default value is NULL.
 * @param info default value is NULL.
 * @param bitmapinfo default value is NULL.
 *
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2007-06-07 new created
 * @date 2008-02-01 Adding two arguments
 */
ImageData::ImageData(const char *name, 
					 const BITMAPINFO* info, 
					 const unsigned int* bittpattern)
{
  this->m_texid = 0xFFFFFFFF;
  if( info == NULL || bittpattern == NULL ){
	this->m_bitpattern = NULL;
	this->m_height = 0;
	this->m_width = 0;
	this->m_memory_height = 0;
	this->m_memory_width = 0;
  }else{
	this->setBitmapBufferMemory(info->bmiHeader.biWidth,
								info->bmiHeader.biHeight);
	for( int i = 0; i < info->bmiHeader.biHeight; i++){
	  for( int j = 0; j < info->bmiHeader.biWidth; j++){
		this->setPixel(j, i, bittpattern[i*info->bmiHeader.biWidth + j]);
	  }
    }
  }
  
  this->m_name = NULL;
  if( name != NULL ){
	this->setM_name(string(name));
	cout << "Name of ImageData is " << this->m_name << endl;
  }
}


/**
 * release #m_bitpattern & #m_name
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2006-06-21
 */
ImageData::~ImageData()
{
  if( this->m_bitpattern != NULL ){
	delete this->m_bitpattern;
  }
  if( this->m_name != NULL ){
	delete this->m_name;
  }
#ifdef DEBUG
  cout << "ImageData's destructor" << endl;
#endif
}

/**
 * \note
 * @param arg set #m_name
 * @version 1.0
 * @author suzuki ryoutoku
 * @date 2006-08-28
 */
void ImageData::setM_name(const string& arg)
{
  if( arg.size() == 0 ) return;
  if( this->m_name != NULL ){
	delete [] this->m_name;
  }
  int counter = 0;
  int index = 0;
  for( int i = arg.size() - 1; i >= 0; i--){
	if( arg.c_str()[i] =='\\'){
	  index = i;
	}
	counter++;
  }
  if( index != 0 ){
	this->m_name = new char[counter];
	strcpy( this->m_name, &(arg.c_str()[index+1]));
  }else{
	this->m_name = new char[arg.size() + 1];
	strcpy( this->m_name, arg.c_str());
  }
}


/**
 * change pixel color
 * \note
 * @param x pixel order
 * @param y pixel order
 * @param R red 0x00 < R < 0xFF
 * @param G green 0x00 < G < 0xFF
 * @param B blue 0x00 < B < 0xFF
 * @param A alpha 0x00 < A < 0xFF
 * @date 2007-06-07
 * @author suzuki ryoutoku
 */
bool ImageData::setPixel(const unsigned int& x, 
						 const unsigned int& y,
						 const unsigned char& R,
						 const unsigned char& G,
						 const unsigned char& B,
						 const unsigned char& A)
{
  if( this->m_memory_width < x ) return false;
  if( this->m_memory_height < y ) return false;

  unsigned int tmpR = (unsigned int)R;
  unsigned int tmpG = (unsigned int)G;
  unsigned int tmpB = (unsigned int)B;
  unsigned int tmpA = (unsigned int)A;
  
  this->m_bitpattern[ x + y * this->m_memory_width]
	= ((tmpA<<24)&0xFF000000)  
	+ ((tmpB<<16)&0xFF0000) 
	+ ((tmpG<<8)&0xFF00) 
	+ tmpR;
  
  return true;
}

/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-2
 */
bool ImageData::setPixel(const unsigned int& x, 
						 const unsigned int& y,
						 const unsigned int pixel)
{
  this->m_bitpattern[ x + y * this->m_memory_width] 
	= ((0xFF<<24)&0xFF000000)+pixel;
  return true;
}

/**
 * Please call (ImageDataManager::setTransmission), if you external process.
 * @author suzuki ryoutoku
 * @date 2007-6-11
 * @version 1.0
 */
void ImageData::setTransmission(unsigned int R,
								unsigned int G, 
								unsigned int B)
{
  for( unsigned int i = 0; i < this->m_memory_height; i ++){
	for( unsigned int j = 0; j < this->m_memory_width; j++){
	  if((( this->m_bitpattern[i*this->m_memory_width + j]>>16)&0xFF) == B ){
		if(((this->m_bitpattern[i*this->m_memory_width+j]>>8)&0xFF) == G ){
		  if( (this->m_bitpattern[i*this->m_memory_width+j]&0xFF) == R ){
			this->m_bitpattern[i*this->m_memory_width+j] 
			  = ((B <<16)&0xFF0000) + ((G<<8)&0xFF00) + R;
		  }
		}
	  }
	}
  }
}


/**
 * get pixel color
 * \note
 * @param x x order
 * @param y y order
 * @param R red
 * @param G green
 * @param B blue
 * @param A alpha
 * @date 2007-06-07
 * @author suzuki ryoutoku
 */
bool ImageData::getPixel(const unsigned int& x, 
						 const unsigned int& y,
						 unsigned int* rgba)
{
  if( this->m_memory_width < x ) return false;
  if( this->m_memory_height < y ) return false;
  *rgba =  this->m_bitpattern[ x + y * this->m_memory_width];
  return true;
}

/**
 * acquire memory for m_bitpattern
 * \note
 * Forcibly, memory size is power of 2.
 * @param iwidth image's width
 * @param iheight image's height
 * @return false is error
 * @author suzuki ryoutoku
 * @date 2007-06-07
 * @version 1.0
 */
bool ImageData::setBitmapBufferMemory(int iwidth, int iheight)
{
  int i,j;
  // If data size is power of 2
  this->m_width = iwidth;
  this->m_height = iheight;
  if( true == this->isPowerOf2() ){
	this->m_memory_width = this->m_width;
	this->m_memory_height = this->m_height;
	this->m_bitpattern 
	  = new unsigned int[ this->m_memory_width*this->m_memory_height ];
	return true;
  }

  // If data size is not power of 2

  // computing memory width 
  for( i = 0; i < 30; i++ ){
	unsigned int value = 2 << i;
	if( value >= this->m_width ){
	  this->m_memory_width = value;
	  break;
	}
  }
  if( i == 30 ) return false;
  
  
  // computing memory height
  for( j = 0; j < 30; j++ ){
	unsigned int value = 2 << j;
	if( value >= this->m_height ){
	  this->m_memory_height = value;
	  break;
	}
  }
  if( j == 30 ) return false;

#ifdef DEBUG
  cout << "mem width = " << this->m_memory_width << endl;
  cout << "mem height = " << this->m_memory_height << endl;
#endif
  

  this->m_bitpattern 
	= new unsigned int[ this->m_memory_width * this->m_memory_height ];
  
  for(unsigned int k = 0; k < this->m_memory_height*this->m_memory_width; k++){
	this->m_bitpattern[k] = 0x00000000;
  }
  
  return true;
}

/**
 * To check whether width and height is power of 2 or not.
 * @return false is error
 * @author suzuki ryoutoku
 * @date 2006-06-21
 * @version 1.0
 */
bool ImageData::isPowerOf2(void)
{
  bool flag_width = true;
  bool flag_height = true;
  
  for( int i = 0; i < 30; i++ ){
	unsigned int value = 2 << i;
	if( value == this->m_width ){
	  flag_width = false;
	}
	if( value == this->m_height ){
	  flag_height = false;
	}
	if( !flag_height && !flag_width ){
	  return true;
	}
  }
  
  if( flag_height || flag_width ){
#ifdef DEBUG
	cout << "[ImageData]width & height is not power of 2" << endl;
#endif
  }
  return false;
}


//=============================================================================
//	Define ImageData's class method
//=============================================================================
/**
 * To load bitmap file header
 * @param fp pointer of file
 * @param header bitmap header
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2007-06-08
 */
bool ImageData::LoadBitMapFileHeader(FILE* fp, BITMAPFILEHEADER* header)
{
  if( fp == NULL ) return false;
  if( header == NULL ) return false;
  
  unsigned char check[2];
  
  fread( &check, sizeof( char ), 2, fp);
  
  if( check[0] != 'B' || check[1] != 'M' ){
	return false;
  }
  
  header->bfType = (check[1] << 8)  + check[0];
  
  fread( &(header->bfSize), sizeof( int ), 1, fp);
  fread( &(header->bfReserved1), sizeof( short ), 1, fp);
  fread( &(header->bfReserved2), sizeof( short ), 1, fp);
  fread( &(header->bfOffBits), sizeof( int ), 1, fp);
  
  return true;
}


/**
 * To load header information of bitmap file
 * @param fp pointer of file
 * @param info information of BITMAP
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2007-06-08
 */
bool ImageData::LoadBitMapFileHedaerInfo(FILE* fp, BITMAPINFO* info)
{
  fread( &(info->bmiHeader), sizeof( BITMAPINFOHEADER ), 1, fp);
  
  // when the bitmapfile have color table
  if( info->bmiHeader.biBitCount == 8){
	// The color table lie later 54 byte
	fseek( fp, 54 , SEEK_SET );
	
	int size = sizeof( RGBQUAD ) * info->bmiHeader.biClrImportant;
	
	// acquire memory for color table
	for( int i = 0; i < info->bmiHeader.biClrImportant; i++ ){
	  	unsigned int tmpR = 0;
		unsigned int tmpG = 0;
		unsigned int tmpB = 0;
		unsigned int resrved = 0;
		fread( &tmpR, sizeof(char), 1, fp);
		fread( &tmpG, sizeof(char), 1, fp);
		fread( &tmpB, sizeof(char), 1, fp);
		fread( &resrved, sizeof(char), 1, fp);
		info->bmiColors[i].rgbBlue = tmpB;
		info->bmiColors[i].rgbRed = tmpR;
		info->bmiColors[i].rgbGreen = tmpG;
	}
  }
  
  return true;
}



/**
 * To load bitpattern, only 24bit
 * @param fp pointer of file
 * @param header bitmap header
 * @param info bitmap information
 * @version 1.0
 * @author suzuki ryoutoku
 * @date 2007-06-08
 */
bool ImageData::LoadBitMapFile24BitPattern(FILE* fp, 
										   ImageData* image,
										   BITMAPFILEHEADER* header, 
										   BITMAPINFO* info)
{
  // set position of file's pointer pixel data
  fseek( fp, header->bfOffBits, SEEK_SET );
  
  for( int i = 0; i < info->bmiHeader.biHeight; i++){
    for( int j = 0; j < info->bmiHeader.biWidth; j++){
      unsigned int tmpR = 0;
      unsigned int tmpG = 0;
      unsigned int tmpB = 0;
      fread( &tmpR, sizeof(char), 1, fp);
      fread( &tmpG, sizeof(char), 1, fp);
      fread( &tmpB, sizeof(char), 1, fp);
	  image->setPixel(j, i, tmpB, tmpG, tmpR, 0xFF);
    }
    // skip padding data
    int padding =  (info->bmiHeader.biWidth * 3) % 4;
    if( padding != 0 ){
      padding = 4 - padding;
#ifdef DEBUG
	  cout << "padding" << endl;
#endif
      for( int k = 0; k < padding; k++){
        char tmp;
        fread( &tmp, sizeof(char), 1, fp);
      }
    }
  }

  return true;
}

/**
 * This method is to load bitpattern with color table.
 * \note
 * The color table is equiped at BITMAPINFO struct.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-7-24
 */
bool ImageData::LoadBitMapFileWithColorTable(FILE* fp, 
											 ImageData* image,
											 BITMAPFILEHEADER* header, 
											 BITMAPINFO* info)
{
  fseek( fp, header->bfOffBits, SEEK_SET );
  for( int i = 0; i < info->bmiHeader.biHeight; i++){
    for( int j = 0; j < info->bmiHeader.biWidth; j++){
      unsigned char index;
      fread( &index, sizeof(unsigned char), 1, fp);
	  image->setPixel(j, i, 
					  info->bmiColors[index].rgbBlue, 
					  info->bmiColors[index].rgbGreen, 
					  info->bmiColors[index].rgbRed, 
					  0xFF);
    }
    // skip padding data
    int padding =  (info->bmiHeader.biWidth * 3) % 4;
    if( padding != 0 ){
      padding = 4 - padding;
#ifdef DEBUG
	  cout << "padding" << endl;
#endif
      for( int k = 0; k < padding; k++){
        char tmp;
        fread( &tmp, sizeof(char), 1, fp);
      }
    }
  }
  return true;
}



//=============================================================================
//	Define's ImageDataManager method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2007-6-10
 * @version 1.0
 */
ImageDataManager::ImageDataManager(void)
{
}

/**
 * @author suzuki ryoutoku
 * @date 2007-6-10
 * @version 1.0
 */
ImageDataManager::~ImageDataManager()
{
}


/**
 *
 * @author suzuki ryoutoku
 * @date 2007-6-10
 * @version 1.0
 */
unsigned int ImageDataManager::createImageData(const string& filepass)
{
  if( this->getTexId(filepass) != 0xFFFFFFFF ) return this->getTexId(filepass);

  FILE* fp;
  
  if( (fp = fopen( filepass.c_str(), "rb" ) ) == NULL ) return 0xFFFFFFFF;
  
  BITMAPFILEHEADER header;
  BITMAPINFO info;
  info.bmiColors = NULL;
  
  // load file hader
  ImageData::LoadBitMapFileHeader( fp, &header);
  
  // load bitmapinfo
  ImageData::LoadBitMapFileHedaerInfo( fp, &info);
  
  ImageData* retval = new ImageData(filepass.c_str());
  
  // load bitpattern
  switch( info.bmiHeader.biBitCount ){
  case 2:
#ifdef DEBUG
	cout << "bitpattern is 2 : error\n";
#endif
	delete retval;
	fclose(fp);
	return 0xFFFFFFFF;
  case 8:
#ifdef DEBUG
	cout << "bitpattern is 8 : error\n";
#endif
	if( info.bmiColors == NULL ){
	  return 0xFFFFFFFF;
	}
	retval->setBitmapBufferMemory(info.bmiHeader.biWidth,
								  info.bmiHeader.biHeight);
	ImageData::LoadBitMapFileWithColorTable(fp, retval, &header, &info);
	break;
  case 16:
#ifdef DEBUG
	cout << "bitpattern is 16 : error\n";
#endif
	fclose(fp);
	delete retval;
	return 0xFFFFFFFF;
	
  case 24:
	cout << "width = " << info.bmiHeader.biWidth << "height = " 
		   << info.bmiHeader.biHeight << endl;

	retval->setBitmapBufferMemory(info.bmiHeader.biWidth,
								  info.bmiHeader.biHeight);
	ImageData::LoadBitMapFile24BitPattern(fp, retval, &header, &info);
	break;
	
  default:
#ifdef DEBUG
	cout << "This bitpattern is not support\n";
#endif
	delete retval;
	if( info.bmiColors != NULL ) delete [] info.bmiColors;
	fclose(fp);
	return 0xFFFFFFFF;
  }
  
  fclose(fp);

  this->assignTexId(retval);
  this->m_imagedatas.push_back(retval);
  if( info.bmiColors != NULL ) delete [] info.bmiColors;
  return retval->m_texid;
}

/**
 * @author suzuki ryoutoku
 * @date 2007-6-10
 * @version 1.0
 */
unsigned int ImageDataManager::getTexId(const string& arg)
{
  if( arg.size() == 0 ) return 0xFFFFFFFF;
  char tmp[256];
  int counter = 0;
  int index = 0;
  for( int i = arg.size() - 1; i >= 0; i--){
	if( arg.c_str()[i] =='\\'){
	  index = i;
	}
	counter++;
  }
  if( index != 0 ){
	strcpy( tmp, &(arg.c_str()[index+1]));
  }else{
	strcpy( tmp, arg.c_str());
  }
  

  list<ImageData*>::iterator ite = this->m_imagedatas.begin();
  while( ite != this->m_imagedatas.end() ){
	if( strstr( tmp, (*ite)->m_name ) ){
	  return (*ite)->getM_texid();
	}
	ite++;
  }
  return 0xFFFFFFFF;
}

/**
 * To remove texture object 
 * \note
 * This method is not removing arg from m_imagedatas , only texture 
 * object for opengl.
 * @param arg
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2006-06-11
 */
bool ImageDataManager::cancelImageData(ImageData* arg)
{
  
  if( arg->m_texid == 0xFFFFFFFF ) return false;

  ::glDeleteTextures(1, (unsigned int*)(&(arg->m_texid)) );
  arg->m_texid = 0xFFFFFFFF;
  return true;
}

/**
 *
 * @author r-suzuki
 * @date 2008-12-9
 * @version 1.0
 */
bool ImageDataManager::removeImageData(unsigned int texid)
{
  list<library::graphics::ImageData*>::iterator ite = m_imagedatas.begin();
  while( ite != m_imagedatas.end() ){
	if( (*ite)->m_texid == texid ){
	  ::glDeleteTextures(1, (unsigned int*)(&((*ite)->m_texid)) );
	  delete *ite;
	  m_imagedatas.erase(ite);
	  return true;
	}
  }
  return false;
}


/**
 * To regist (ImageData) OpenGL
 * \note
 * When registing is success, set opengl's paramter to (ImageData::m_texid).
 * @param image
 * @author suzuki ryoutoku
 * @date 2007-6-10
 * @version 1.0
 */
unsigned int ImageDataManager::assignTexId(ImageData* image)
{
  unsigned int texid = 0xFFFFFFFF;


  ::glGenTextures(1 , &texid );
  ::glBindTexture(GL_TEXTURE_2D , texid);

  // bit pattern alignment is 4byte, because data type is unsigned int.
  ::glPixelStorei(GL_UNPACK_ALIGNMENT, 4);

  // regist bitpattern
  ::glTexImage2D( GL_TEXTURE_2D, 
				  0, 
				  GL_RGBA,
				  image->getM_memory_width(),
				  image->getM_memory_height(),
				  0,
				  GL_RGBA,
				  GL_UNSIGNED_BYTE, // always BYTE
				  image->getM_bitpattern() );
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  //::glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
  ::glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

  image->setM_texid(texid);

  this->m_imagedatas.push_back(image);

  return texid;
}


/**
 * This method queryies a image by texture id.
 * @param arg (ImageData::m_texid)
 * @param #m_imagedatas
 * @author suzuki ryoutoku
 * @date 2007-6-11
 * @version 1.0
 */
ImageData* ImageDataManager::getImageData(unsigned int texid)
{
  list<ImageData*>::iterator ite = this->m_imagedatas.begin();
  while( ite != this->m_imagedatas.end() ){
	if( (*ite)->m_texid == texid ){
	  return (*ite);
	}
	ite++;
  }
  return NULL;
}


/**
 * @param arg target to operate
 * @param R default value zero
 * @param G default value zero
 * @param B default value zero
 * @author suzuki ryoutoku
 * @date 2007-6-11
 * @version 1.0
 */
unsigned int ImageDataManager::setTransmission(ImageData* arg, 
											   unsigned int R,
											   unsigned int G, 
											   unsigned int B)
{
  this->cancelImageData(arg);
  arg->setTransmission(R,G,B);
  this->assignTexId(arg);
  return arg->m_texid;
}

/**
 * This method give you the instance of ImageDataManager.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-2
 */
ImageDataManager* ImageDataManager::getInstance(void)
{
  return &instance;
}

//=============================================================================
//	ImageDataManager's static member
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-2
 */
ImageDataManager ImageDataManager::instance;

//=============================================================================
//	DrawBox's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2007-9-25
 * @version 1.0
 */
DrawBox::DrawBox(GraphicalCommand::CommandType arg) :
  GraphicalCommand(arg)
{
  this->GraphicalCommand::setM_state( DrawBox::LIGHTING);
  this->m_coord[0] = Vector<double>(0.0,0.0,0.0,1.0);
  this->m_coord[1] = Vector<double>(1.0,0.0,0.0,1.0);
  this->m_coord[2] = Vector<double>(1.0,0.0,1.0,1.0);
  this->m_coord[3] = Vector<double>(0.0,0.0,1.0,1.0);
  this->m_coord[4] = Vector<double>(0.0,1.0,0.0,1.0);
  this->m_coord[5] = Vector<double>(1.0,1.0,0.0,1.0);
  this->m_coord[6] = Vector<double>(1.0,1.0,1.0,1.0);
  this->m_coord[7] = Vector<double>(0.0,1.0,1.0,1.0);

  this->m_normal[0] = Vector<double>( 0.0, 0.0, 1.0, 0.0);
  this->m_normal[1] = Vector<double>( 0.0,-1.0, 0.0, 0.0);
  this->m_normal[2] = Vector<double>( 0.0, 1.0, 0.0, 0.0);
  this->m_normal[3] = Vector<double>( 0.0, 0.0,-1.0, 0.0);
  this->m_normal[4] = Vector<double>(-1.0, 0.0, 0.0, 0.0);
  this->m_normal[5] = Vector<double>( 1.0, 0.0, 0.0, 0.0);

  this->m_color[0] = Color<float>( 0.7, 0.0, 0.0, 1.0);
  this->m_color[1] = Color<float>( 0.0, 0.7, 0.0, 1.0);
  this->m_color[2] = Color<float>( 0.0, 0.0, 0.7, 1.0);
  this->m_color[3] = Color<float>( 0.0, 0.7, 0.7, 1.0);
  this->m_color[4] = Color<float>( 0.7, 0.7, 0.0, 1.0);
  this->m_color[5] = Color<float>( 0.7, 0.0, 0.7, 1.0);
  

  this->m_face_index[0][0] = 2;
  this->m_face_index[0][1] = 6;
  this->m_face_index[0][2] = 7;
  this->m_face_index[0][3] = 3;
  this->m_face_index[1][0] = 0;
  this->m_face_index[1][1] = 1;
  this->m_face_index[1][2] = 2;
  this->m_face_index[1][3] = 3;
  this->m_face_index[2][0] = 7;
  this->m_face_index[2][1] = 6;
  this->m_face_index[2][2] = 5;
  this->m_face_index[2][3] = 4;
  this->m_face_index[3][0] = 4;
  this->m_face_index[3][1] = 5;
  this->m_face_index[3][2] = 1;
  this->m_face_index[3][3] = 0;
  this->m_face_index[4][0] = 7;
  this->m_face_index[4][1] = 4;
  this->m_face_index[4][2] = 0;
  this->m_face_index[4][3] = 3;
  this->m_face_index[5][0] = 5;
  this->m_face_index[5][1] = 6;
  this->m_face_index[5][2] = 2;
  this->m_face_index[5][3] = 1;
#ifdef DEBUG
  cout << "create DrawBox " << endl;
#endif
}


/**
 * @author suzuki ryoutoku
 * @date 2007-9-25
 * @version 1.0
 */
DrawBox::~DrawBox()
{
#ifdef DEBUG
  cout << "destroy DrawBox " << endl;
#endif
}


/**
 * To draw box
 * \note
 *
 * @param screen target screen
 *
 * @author suzuki ryoutoku
 * @date 2007-9-25
 * @version 1.0
 */
int DrawBox::execute(Screen* screen)
{
  ::glMatrixMode(GL_MODELVIEW);
  //::glLoadIdentity();
  this->getM_coordinate()->settingOpenGL();

  // enable vertex array
  ::glEnableClientState( GL_VERTEX_ARRAY );

  // regist the pointer of vertex array for OpenGL
  ::glVertexPointer( 4, GL_DOUBLE, 0, &(this->m_coord[0]));
  if( this->GraphicalCommand::getM_state() & GraphicalCommand::LIGHTING ){
#if 0
	Color<float> color1(0.7, 0.0, 0.0, 1.0);
	::glMaterialfv(GL_FRONT,GL_DIFFUSE,  color1.color);
#endif
	Color<float> color2(0.0, 0.0, 0.0, 0.0);
	::glMaterialfv(GL_FRONT,GL_AMBIENT,  color2.color);
	Color<float> color3(0.0, 0.0, 0.0, 0.0);
	::glMaterialfv(GL_FRONT,GL_SPECULAR, color3.color);
	
	// enable to change material color within glBegin ~ glEnd
	::glEnable( GL_COLOR_MATERIAL );
	
	// changing color material is diffuse
	::glColorMaterial(GL_FRONT, GL_DIFFUSE);
  }else {
	::glDisable(GL_LIGHTING);
  }

#if 0
  ::glEnable(GL_BLEND);
  ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif

  ::glEnable( GL_POLYGON_OFFSET_FILL );
  ::glPolygonOffset( 3.0, 3.0 );
  ::glPolygonMode( GL_FRONT, GL_FILL );
  ::glBegin(GL_QUADS);
  {
	for( int i = 0; i < 6; i++){
	  ::glNormal3dv( this->m_normal[i].vec);
	  ::glColor3fv( this->m_color[i].color);
	  for( int j = 0;j < 4; j++){
		::glArrayElement(this->m_face_index[i][j]);
	  }
	}
  }
  ::glEnd();
  ::glDisable( GL_POLYGON_OFFSET_FILL );

  if( this->GraphicalCommand::getM_state() & GraphicalCommand::WIRE_FRAME ){
	::glEnable( GL_POLYGON_OFFSET_LINE);
	::glPolygonOffset( 0.5, 0.5 );
	::glPolygonMode( GL_FRONT, GL_LINE );
	::glLineWidth( 1.5 );
	::glColor3d( 0.0, 0.0, 0.0);
	for( int i = 0; i < 6; i++){
	  ::glBegin(GL_LINE_LOOP);
	  {
		
		for( int j = 0;j < 4; j++){
		  ::glArrayElement(this->m_face_index[i][j]);
		}
	  }
	  ::glEnd();
	}
	::glDisable( GL_POLYGON_OFFSET_LINE);
  }
  ::glDisableClientState( GL_VERTEX_ARRAY );

  if( 0 == (this->getM_state()&GraphicalCommand::LIGHTING) ){
	::glEnable(GL_LIGHTING);
  }

  return 0;
}

//=============================================================================
//	DrawString's method
//=============================================================================
/**
 * @author suzuki ryoutoku 
 * @date 2007-10-20
 * @version 1.0
 */
DrawString::DrawString(GraphicalCommand::CommandType arg) :
  GraphicalCommand(arg)
{
  memset(this->m_message, 0, 256);
  this->m_line_number = 0;
}

/**
 * @author suzuki ryoutoku 
 * @date 2007-10-20
 * @version 1.0
 */
DrawString::~DrawString()
{
}

/**
 *
 * @param arg array size is within 256
 *
 * @author suzuki ryoutoku 
 * @date 2007-10-20
 * @version 1.0
 */
void DrawString::setM_message(char* arg)
{
  if( strlen(arg) > 256 ){
	strcpy(this->m_message,"error message array over");
  }else{
	strcpy(this->m_message,arg);
  }
  
}


/**
 * when character string is drawed, cancel depth value in opengl.
 * @author suzuki ryoutoku 
 * @date 2007-10-20
 * @version 1.0
 */
int DrawString::execute(Screen* screen)
{
  GLint vp[4];
  bool light_flag = false;
  if( this->GraphicalCommand::getM_state() == 1 ) return 0;

  
  if( screen->getM_type() != Screen::TWO_DIMENSION ){
	// acquire now viewport
	::glGetIntegerv(GL_VIEWPORT, vp);
	// set screen coordinate for 2d
	::glMatrixMode(GL_PROJECTION);
	::glPushMatrix();
	::glLoadIdentity();
	::glViewport( (GLint)screen->getM_rect()->left, 
				  (GLint)screen->getM_rect()->top, 
				  (GLint)screen->getM_rect()->right, 
				  (GLint)screen->getM_rect()->bottom);
	GLdouble width 
	  = screen->getM_rect()->right - screen->getM_rect()->left;
	GLdouble height 
	  = screen->getM_rect()->bottom - screen->getM_rect()->top;
	::glOrtho( 0.0, 
			   width, 
			   0.0, 
			   height,
			   -1.0,
			   1.0);
  }

  // enable light
  if( ::glIsEnabled(GL_LIGHTING) != GL_FALSE ){
	::glDisable(GL_LIGHTING);
	light_flag = true;
  }

  ::glClear( GL_DEPTH_BUFFER_BIT );

  // setting my coordinate
  ::glMatrixMode(GL_MODELVIEW);
  ::glLoadIdentity();

  ::glColor3f( 0.0, 0.0, 0.0 );
  ::glRasterPos2i( 0, 
				   // 20 is font height, Fix this at a later date.
				   screen->getM_rect()->bottom - 20*(1+this->m_line_number));
  ::glListBase( screen->getM_rm()->getM_font_number() );

  ::glCallLists(strlen(this->m_message), GL_UNSIGNED_BYTE, this->m_message);

  if( light_flag == true ){
	::glEnable( GL_LIGHTING);
  }
  if( screen->getM_type() != Screen::TWO_DIMENSION ){
	::glMatrixMode( GL_PROJECTION );
	::glPopMatrix();
	
	::glViewport(vp[0], vp[1], vp[2], vp[3]);
  }
  ::glMatrixMode(GL_MODELVIEW);
  ::glPopMatrix();

  return 0;
}



//=============================================================================
//	TestCommand's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2007-9-25
 * @version 1.0
 */
TestCommand::TestCommand(GraphicalCommand::CommandType arg) :
  GraphicalCommand(arg)
{
#ifdef DEBUG
  cout <<"create TestCommand" << endl;
#endif
  this->m_function=0;
#if 0
  this->getM_coordinate()->setM_pivot(Vector<double>(0.0,0.0,-6.0,0.0));
  this->m_vertex[0] = Vector<double>(0.0,0.0,0.0,1.0);
  this->m_vertex[1] = Vector<double>(1.0,0.0,0.0,1.0);
  this->m_vertex[2] = Vector<double>(1.0,0.0,1.0,1.0);
  this->m_vertex[3] = Vector<double>(0.0,0.0,1.0,1.0);
  this->m_vertex[4] = Vector<double>(0.0,1.0,0.0,1.0);
  this->m_vertex[5] = Vector<double>(1.0,1.0,0.0,1.0);
  this->m_vertex[6] = Vector<double>(1.0,1.0,1.0,1.0);
  this->m_vertex[7] = Vector<double>(0.0,1.0,1.0,1.0);

  this->m_normal[0] = Vector<double>( 0.0, 0.0, 1.0, 0.0);
  this->m_normal[1] = Vector<double>( 0.0,-1.0, 0.0, 0.0);
  this->m_normal[2] = Vector<double>( 0.0, 1.0, 0.0, 0.0);
  this->m_normal[3] = Vector<double>( 0.0, 0.0,-1.0, 0.0);
  this->m_normal[4] = Vector<double>(-1.0, 0.0, 0.0, 0.0);
  this->m_normal[5] = Vector<double>( 1.0, 0.0, 0.0, 0.0);

  this->m_color[0] = Color<float>( 0.7, 0.0, 0.0, 1.0);
  this->m_color[1] = Color<float>( 0.0, 0.7, 0.0, 1.0);
  this->m_color[2] = Color<float>( 0.0, 0.0, 0.7, 1.0);
  this->m_color[3] = Color<float>( 0.0, 0.7, 0.7, 1.0);
  this->m_color[4] = Color<float>( 0.7, 0.7, 0.0, 1.0);
  this->m_color[5] = Color<float>( 0.7, 0.0, 0.7, 1.0);
#endif
}


/**
 * @author suzuki ryoutoku
 * @date 2007-9-25
 * @version 1.0
 */
TestCommand::~TestCommand()
{
#ifdef DEBUG
  cout <<"destroy TestCommand" << endl;
#endif
}


/**
 * \note
 * now draw method is triangle strip
 *
 * @param screen 
 *
 * @author suzuki ryoutoku
 * @date 2007-9-25
 * @version 1.0
 */
int TestCommand::execute(Screen* screen)
{
  this->m_function(screen);
#if 0
  ::glMatrixMode(GL_MODELVIEW);
  //::glLoadIdentity();
  this->getM_coordinate()->settingOpenGL();

  ::glEnableClientState( GL_VERTEX_ARRAY );

  ::glVertexPointer( 4, GL_DOUBLE, 0, &(this->m_vertex[0]));

  Color<float> color2(0.0, 0.0, 0.0, 0.0);
  ::glMaterialfv(GL_FRONT,GL_AMBIENT,  color2.color);
  Color<float> color3(0.0, 0.0, 0.0, 0.0);
  ::glMaterialfv(GL_FRONT,GL_SPECULAR, color3.color);
  
  ::glEnable( GL_COLOR_MATERIAL );
  
  ::glColorMaterial(GL_FRONT, GL_DIFFUSE);

  ::glEnable( GL_POLYGON_OFFSET_FILL );
  ::glPolygonOffset( 0.5, 0.5 );
  ::glPolygonMode( GL_FRONT, GL_FILL );

  ::glBegin(GL_TRIANGLE_STRIP);
  {
	
	::glArrayElement(2);
	::glArrayElement(6);
	::glNormal3dv( this->m_normal[0].vec);
	::glColor3fv( this->m_color[0].color);
	::glArrayElement(3);

	::glNormal3dv( this->m_normal[0].vec);
	::glColor3fv( this->m_color[1].color);
	::glArrayElement(7);

	::glNormal3dv( this->m_normal[4].vec);
	::glColor3fv( this->m_color[2].color);
	::glArrayElement(4);
  }
  ::glEnd();
  ::glDisable( GL_POLYGON_OFFSET_FILL );
  ::glDisableClientState( GL_VERTEX_ARRAY );
#endif  
  return 0;
}

/**
 *
 * \note
 *
 *
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-3-6
 */
void TestCommand::setOriginalFunction(void (*function)(Screen* screen))
{
  this->m_function=function;
}

//=============================================================================
//	Model's method
//=============================================================================
/**
 * \note
 * @param flag when flag is true, create box.
 *
 * @author suzuki ryoutoku
 * @date 2007-10-12
 * @version 1.0
 */
Model::Model(bool flag, GraphicalCommand::CommandType arg) :
  GraphicalCommand(arg)
{
  this->_polygon_sum=0;
  this->_vertex_sum=0;
  _drawingmethod=VERTEX_ARRAY;
  //this->setM_state(GraphicalCommand::LIGHTING ^ GraphicalCommand::POINTS);
  this->setM_state(GraphicalCommand::LIGHTING);
  if( flag == true){
	appendPolygonBody(PolygonBody::CreateQubicPolygonBody());
	this->createCenter();
  }
}

/**
 * Release memory.
 * @author suzuki ryoutoku 
 * @date 2007-10-21
 * @version 1.0
 */
Model::~Model()
{
  vector<library::graphics::PolygonBody*>::iterator ite =  _bodies.begin();
  while( ite != _bodies.end() ){
	for( size_t i = 0; i < (*ite)->_groups.size(); i++ ){
	  if( (*ite)->_groups[i]->_type == Group::TEXTURE ){
		if( (*ite)->_groups[i]->_texid != -1 ){
		  ImageDataManager* idm = this->getM_target_rm()->get_idm();
		  idm->removeImageData((*ite)->_groups[i]->_texid);
		}
	  }
	}
	delete (*ite);
	ite++;
  }
  _bodies.clear();
}

/**
 * This method draws 3d model data.
 * \note
 * Recursively calling all polygon in group in volume.
 *
 * @author suzuki ryoutoku 
 * @date 2007-10-21
 * @version 1.0
 */
int Model::execute(Screen* screen)
{
  ::glMatrixMode(GL_MODELVIEW);
  ::glPushMatrix();
  ::glLoadIdentity();

  this->getM_coordinate()->settingOpenGL();

  if( this->getM_state() & GraphicalCommand::LIGHTING ){
	::glEnable(GL_LIGHTING);
	Color<float> color1(1.0, 1.0, 1.0, 1.0);
	::glMaterialfv(GL_FRONT,GL_DIFFUSE,  color1.color);	
  	Color<float> color2(0.0, 0.0, 0.0, 0.0);
	::glMaterialfv(GL_FRONT,GL_AMBIENT,  color2.color);
	Color<float> color3(0.0, 0.0, 0.0, 0.0);
	::glMaterialfv(GL_FRONT,GL_SPECULAR, color3.color);

	// enable variable material color within glBegin~glEnd
	::glEnable( GL_COLOR_MATERIAL );
	
	// variable color is diffuse
	::glColorMaterial(GL_FRONT, GL_DIFFUSE);
  }else {
	::glDisable(GL_LIGHTING);
  }

  ::glEnableClientState( GL_VERTEX_ARRAY );
  ::glEnableClientState( GL_TEXTURE_COORD_ARRAY );

  ::glEnable( GL_POLYGON_OFFSET_FILL );
  
  ::glEnable( GL_COLOR_MATERIAL );
  ::glPolygonMode( GL_FRONT, GL_FILL );

  for( size_t i = 0; i < _bodies.size(); i++){
	if( _bodies[i]->_state != 1 ) continue;
	::glVertexPointer( 4, GL_DOUBLE, 0, (_bodies[i]->_vertex));
#if 0
	if( _bodies[i]->_uv != NULL ){
	  ::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
	  ::glTexCoordPointer(2,GL_FLOAT,sizeof(Vector2D<float>),_bodies[i]->_uv);
	}
#endif
	
	for( size_t j = 0; j < _bodies[i]->_groups.size() ; j++ ){
	  Group* group = _bodies[i]->_groups[j];
	  if(_bodies[i]->_groups[j]->get_state() != 1 ) continue;
	  if(_bodies[i]->_groups[j]->_targets.size() == 0 ) continue;
	  if(_bodies[i]->_uv != NULL && _bodies[i]->_groups[j]->get_texid() !=-1){
		::glEnableClientState( GL_TEXTURE_COORD_ARRAY );
		::glTexCoordPointer(2,GL_FLOAT,
							sizeof(Vector2D<float>),_bodies[i]->_uv);
	  }else{
		::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
	  }
	  switch( _bodies[i]->_groups[j]->_target_type ){
	  case Group::POLYGON:
	  case Group::VERTEX:
		::glDisable(GL_LIGHTING);
		_bodies[i]->_groups[j]->draw(_bodies[i]);
		if( this->getM_state() & GraphicalCommand::LIGHTING ){
		  ::glEnable(GL_LIGHTING);
		}
		break;
	  case Group::CLUSTER:
		if( _drawingmethod == VERTEX_ARRAY ){
		  _bodies[i]->_groups[j]->draw(_bodies[i]);
		}
		break;
	  case Group::STRIP_CLUSTER:
		if( _drawingmethod == STRIP ){
		  _bodies[i]->_groups[j]->draw(_bodies[i]);
		}else if( _drawingmethod == STRIP_WITH_COLOR ){
		  _bodies[i]->_groups[j]->draw(_bodies[i], 1);
		}
		break;
	  }
	}
	if( _bodies[i]->_uv != NULL ){
	  ::glDisableClientState( GL_TEXTURE_COORD_ARRAY );
	}
  }
  ::glDisable( GL_POLYGON_OFFSET_FILL );

  if( this->GraphicalCommand::getM_state() & GraphicalCommand::WIRE_FRAME ){
	::glEnable( GL_POLYGON_OFFSET_LINE);
	::glPolygonOffset( 0.0, 0.0 );
	::glPolygonMode( GL_FRONT, GL_LINE );
	::glLineWidth( 1.5 );
	::glDisable(GL_LIGHTING);
	::glColor3d( 0.0, 0.0, 0.0);
	for( size_t i = 0; i < _bodies.size(); i++){
	  if( _bodies[i]->_state != 1 ) continue;
	  ::glVertexPointer( 4, GL_DOUBLE, 0, (_bodies[i]->_vertex));
	  for( size_t j = 0;j < _bodies[i]->_face.size(); j++){
		::glBegin(GL_LINE_LOOP);
		for( int k = 0; k < _bodies[i]->_face[j]._type; k++ ){
		  ::glArrayElement(_bodies[i]->_face[j]._connectivity_pointer[k]);
		}
		::glEnd();
	  }
	}
	::glDisable( GL_POLYGON_OFFSET_LINE);
  }
  if( this->GraphicalCommand::getM_state() & GraphicalCommand::POINTS ){
	::glEnable( GL_POLYGON_OFFSET_POINT);
	::glPolygonOffset( 0.0, 0.0 );
	::glPolygonMode( GL_FRONT, GL_POINT );
	::glPointSize( 5.0 );
	::glDisable(GL_LIGHTING);
	::glColor3d( 0.0, 0.0, 0.0);
	for( size_t i = 0; i < _bodies.size(); i++){
	  if( _bodies[i]->_state != 1 ) continue;
	  ::glVertexPointer( 4, GL_DOUBLE, 0, (_bodies[i]->_vertex));
	  ::glBegin(GL_POINTS);
	  for( int j = 0;j < _bodies[i]->_vertex_sum; j++){
		::glArrayElement(j);
	  }
	  ::glEnd();
	}
	::glDisable( GL_POLYGON_OFFSET_POINT);
  }
  
  ::glDisableClientState( GL_VERTEX_ARRAY );
  if( 0 == (this->getM_state()&DrawBox::LIGHTING) ){
	::glEnable(GL_LIGHTING);
  }
  ::glMatrixMode(GL_MODELVIEW);
  ::glPopMatrix();  
  
  return 0;
}

/**
 * Call gl command for selection polygon.
 * @author suzuki ryoutoku
 * @date 2007-12-25
 * @version 1.0
 */
void Model::selectionPolygon(void)
{
  ::glMatrixMode(GL_MODELVIEW);
  ::glLoadIdentity();

  this->getM_coordinate()->settingOpenGL();

  ::glEnableClientState( GL_VERTEX_ARRAY );
  ::glEnable( GL_POLYGON_OFFSET_FILL );
  ::glPolygonOffset( 3.0, 3.0 );
  ::glPolygonMode( GL_FRONT, GL_FILL );

  for( size_t i = 0; i < _bodies.size(); i++){
	::glVertexPointer( 4, GL_DOUBLE, 0, (_bodies[i]->_vertex));
	for( size_t j = 0; j < _bodies[i]->_cluster.size(); j++ ){
	  _bodies[i]->_cluster[j]->selection(_bodies[i]);
	}
	
  }
  ::glDisable( GL_POLYGON_OFFSET_FILL );
  ::glMatrixMode(GL_MODELVIEW);
  ::glPopMatrix();
}

/**
 * Call gl command for selection vertex.
 * @author r-suzuki
 * @date 2008-11-26
 * @version 1.0
 */
void Model::selectionVertex(void)
{
  ::glMatrixMode(GL_MODELVIEW);
  ::glLoadIdentity();

  this->getM_coordinate()->settingOpenGL();

  // enable vertex array
  ::glEnableClientState( GL_VERTEX_ARRAY );

  ::glDisable(GL_LIGHTING);
  ::glPolygonMode( GL_FRONT, GL_POINT );
  ::glEnable( GL_POLYGON_OFFSET_POINT);

  for( size_t i = 0; i < _bodies.size(); i++){
	::glVertexPointer( 4, GL_DOUBLE, 0, (_bodies[i]->_vertex));
	::glPointSize( 10.0 );
	for( int j = 0;j < _bodies[i]->_vertex_sum; j++){
	  ::glLoadName( _bodies[i]->_vertex_id[j] );
	  ::glBegin(GL_POINTS);
	  ::glArrayElement(j);
	  ::glEnd();
	}
  }
  ::glDisable( GL_POLYGON_OFFSET_POINT );
  ::glMatrixMode(GL_MODELVIEW);
  ::glPopMatrix();
}

/**
 * This method toggles a polygon to belong SELECTION Group.
 * @retval 0
 * @author suzuki ryoutoku
 * @date 2007-12-30
 * @version 1.0
 */
int Model::toggleSelectionPolygon(int globalid)
{
  for( size_t i = 0; i < _bodies.size(); i++){
	library::graphics::Group* group = _bodies[i]->queryGroup(Group::SELECTION,
															 Group::POLYGON);
	if( group == NULL ) continue;
	for( size_t j = 0; j < _bodies[i]->_face.size(); j++ ){
	  if( _bodies[i]->_face[j].get_global_id() == globalid ){
		if( false == group->addTarget(j) ){
		  group->removeTarget(j);
		}
		cout << "id=" << _bodies[i]->_face[j].get_global_id() << " ";
		for( int k = 0; k < _bodies[i]->_face[j].get_type(); k++ ){
		  cout << _bodies[i]->_face[j]._connectivity_pointer[k];
		  if( k < (_bodies[i]->_face[j].get_type()-1) ) cout << "-";
		}
		cout << endl;
	  }
	}
  }
  return 0;
}

/**
 *
 * @author r-suzuki
 * @date 2007-12-30
 * @version 1.0
 */
int Model::toggleSelectionVertex(int globalid)
{
  for( size_t i = 0; i < _bodies.size(); i++){
	library::graphics::Group* group = _bodies[i]->queryGroup(Group::SELECTION,
															 Group::VERTEX);
	if( group == NULL ) continue;
	for( size_t j = 0; j < _bodies[i]->_vertex_id.size(); j++ ){
	  if( _bodies[i]->_vertex_id[j] == globalid ){
		if( false == group->addTarget(j) ){
		  group->removeTarget(j);
		}
		cout << "id=" << _bodies[i]->_vertex_id[j];
		cout << " (" << _bodies[i]->_vertex[j].x
			 << "," << _bodies[i]->_vertex[j].y
			 << "," << _bodies[i]->_vertex[j].z
			 << ")";
		if( _bodies[i]->_uv != NULL ){
		  cout << " [" << _bodies[i]->_uv[j].u 
			   << ","  << _bodies[i]->_uv[j].v  <<"]";
		}
		cout << endl;
	  }
	}
  }
  return 0;
}

/**
 * If model has triangle strip clusteres, All triangle strip clusteres is 
 * removed.
 * @author r-suzuki
 * @date 2008-12-24
 * @version 1.0
 */
int Model::removeTriangleStripCluster(void)
{
  for( size_t i = 0; i < _bodies.size(); i++){
	PolygonBody* body = _bodies[i];
	vector<library::graphics::Group*>::iterator gite=body->_groups.begin();
	while( gite != body->_groups.end() ){
	  if( (*gite)->_target_type == Group::STRIP_CLUSTER ){
		body->_groups.erase(gite);
	  }else{
		gite++;
	  }
	}
	vector<library::graphics::Cluster*>::iterator cite=body->_cluster.begin();
	while( cite != body->_cluster.end() ){
	  if( (*cite)->get_type() == Cluster::STRIP_CLUSTER ){
		body->_cluster.erase(cite);
	  }else{
		cite++;
	  }
	}
  }
  return 0;
}


/**
 * To extract volume with specified name
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::PolygonBody* Model::getPolygonBody(const char* name)
{
  for( size_t i = 0; i < _bodies.size(); i++){
	if( 0 == strcmp(_bodies[i]->_name, name) ){
	  return _bodies[i];
	}
  }
  return NULL;
}

/**
 * Create center of all vertex.
 * @author suzuki ryoutoku
 * @date 2007-12-29
 * @version 1.0
 */
void Model::createCenter(void)
{
  Vector<double> retval(0.0,0.0,0.0,0.0);
  int versum = 0;
  for(int i = 0; i < this->_bodies.size(); i++){
	versum += this->_bodies[i]->_vertex_sum;
	for( int j = 0; j < this->_bodies[i]->_vertex_sum; j++ ){
	  retval += this->_bodies[i]->_vertex[j];
	}
  }
  retval /= (double)versum;
  this->getM_coordinate()->setM_local_origin(retval);
}

/**
 * This method compute height, width and depth of model.
 * @author suzuki ryoutoku 
 * @version 1.0
 * @date 2008-1-1
 */
void Model::computeSize(double* width, double* height, double* depth)
{
  // computing width ,height and depth of model data
  double min_x = 0.0;
  double min_y = 0.0;
  double min_z = 0.0;
  double max_x = 0.0;
  double max_y = 0.0;
  double max_z = 0.0;
  for( size_t i = 0; i < _bodies.size(); i++ ){
	for( size_t j = 0; j < _bodies[i]->_vertex_sum; j++ ){
	  if( min_x > _bodies[i]->_vertex[j].x ){
		min_x = _bodies[i]->_vertex[j].x;
	  }
	  if( max_x < _bodies[i]->_vertex[j].x ){
		max_x = _bodies[i]->_vertex[j].x;
	  }
	  if( min_y > _bodies[i]->_vertex[j].y ){
		min_y = _bodies[i]->_vertex[j].y;
	  }
	  if( max_y < _bodies[i]->_vertex[j].y ){
		max_y = _bodies[i]->_vertex[j].y;
	  }
	  if( min_z > _bodies[i]->_vertex[j].z ){
		min_z = _bodies[i]->_vertex[j].z;
	  }
	  if( max_z < _bodies[i]->_vertex[j].z ){
		max_z = _bodies[i]->_vertex[j].z;
	  }
	}
  }
  (*width) = abs(max_x - min_x);
  (*height) = abs(max_y - min_y);
  (*depth) = abs(max_z - min_z);
}


/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-9
 */
void Model::coloring(Color<float> color)
{
  for( size_t i = 0; i < this->_bodies.size(); i ++){
	for( size_t j = 0; j < _bodies[i]->_groups.size(); j++ ){
	  if( Group::TEXTURE == _bodies[i]->_groups[j]->get_type() ){
		_bodies[i]->_groups[j]->set_color(color);
	  }
	}
  }
}

/**
 * This method correspond group data's  texture id with ImageData
 * \note
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-7
 */
void Model::setTextureID(ImageDataManager* idm)
{
  for( size_t i = 0; i < _bodies.size(); i ++ ){
	PolygonBody* body = _bodies[i];
	for( size_t j = 0; j < body->_groups.size(); j++ ){
	  if( body->_groups[j]->_type != Group::TEXTURE ) continue;
	  if( body->_groups[j]->get_texname()[0] == '\0' ) continue;
	  Group* group = body->_groups[j];
	  group->_texid = idm->getTexId(string(group->get_texname()));
	  cout << group->get_name() 
		   << " texfilename=" << group->get_texname()
		   << " texid = " << group->_texid << endl;
	  ImageData* image = idm->getImageData(group->_texid);
	  if( image == NULL ) continue;
	  float mh = image->getM_memory_height();
	  float mw = image->getM_memory_width();
	  float h = image->getM_height();
	  float w = image->getM_width();
	  cout << "memory height" << mh <<endl;
	  cout << "memory with" << mw <<endl;
	  cout << "height" << h <<endl;
	  cout << "width" << w <<endl;
	  if( mh == h && w == mw ) continue;
	  Vector2D<float> tmp(w/mw,h/mh);
	  cout << tmp.u << " " << tmp.v << endl;
	  for( int vindex = 0; vindex < body->_vertex_sum; vindex++){
		body->_uv[vindex] *= tmp;
#if 0
		cout << vindex << ":" 
			 << body->_uv[vindex].u << " " << body->_uv[vindex].v << endl;
#endif
	  }
	}
  }
}

/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
bool library::graphics::Model::appendPolygonBody(library::graphics::PolygonBody* body, bool vertex_numbering)
{
  for( size_t i = 0; i < body->_face.size(); i++ ){
	body->_face[i].set_global_id(_polygon_sum++);
  }
  if( vertex_numbering ){
	for( size_t i = 0; i < body->_vertex_id.size(); i++ ){
	  body->_vertex_id[i] = _vertex_sum++;
	}
  }else{
	for( size_t i = 0; i < body->_vertex_id.size(); i++ ){
	  _vertex_sum++;
	}
  }
  this->_bodies.push_back(body);
}

library::graphics::PolygonBody* 
library::graphics::Model::queryPolygonBody(const char* name)
{
  for(size_t i = 0; i < this->_bodies.size(); i++){
	if( 0 == strcmp(_bodies[i]->_name, name) ){
	  return _bodies[i];
	}
  }
  return NULL;
}

//=============================================================================
//	Group's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::Group::Group(const unsigned int type, 
								const unsigned int target_type,
								const char* texname) : 
  _type(type),
  _target_type(target_type)
{
  _targets.clear();
  _texid = 0xFFFFFFFF;
  memset(_name,'\0',256);
  if( texname != NULL ){
	strcpy(_texname, texname);
  }else{
	memset(_texname,'\0',256);
  }
  _state=1;
  switch( type ){
  case Group::SELECTION:
	_color = Color<float>(1.0, 1.0, 0.0,1.0);
	break;
  case Group::TEXTURE:
	_color = Color<float>(0.7,0.7,0.7,1.0);
	break;
  default:
	_color = Color<float>(1.0, 1.0, 1.0,1.0);
	break;
  }
}

/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::Group::~Group()
{
  _targets.clear();
}

/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
bool library::graphics::Group::removeTarget(int arg)
{
  list<int>::iterator ite = this->_targets.begin();
  while( ite != this->_targets.end() ){
	if( (*ite) == arg ){
	  this->_targets.erase(ite);
	  return true;
	}
	ite++;
  }
  return false;
}

bool library::graphics::Group::addTarget(int arg)
{
  list<int>::iterator ite = this->_targets.begin();
  while( ite != this->_targets.end() ){
	if( (*ite) == arg ){
	  return false;
	}
	ite++;
  }
  _targets.push_back(arg);
  return true;
}

/**
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
list<int>::iterator library::graphics::Group::getTarget(int index)
{
  list<int>::iterator retval = _targets.begin();
  if( index < _targets.size() ){
	int counter = 0;
	while( retval != _targets.end() ){
	  if( counter++ == index ) return retval;
	  retval++;
	}
  }
  return retval;
}

/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
void library::graphics::Group::draw(library::graphics::PolygonBody* body,
									int draw_state)
{
  
  switch( _target_type ){
  case Group::CLUSTER:
  case Group::STRIP_CLUSTER:
	{
	  ::glPolygonOffset( 3.0, 3.0 );
	  ::glColor3fv(_color.color);
	  if( _texid != 0xFFFFFFFF && draw_state == 0){
		::glEnable(GL_TEXTURE_2D);
		::glEnable(GL_BLEND);
		::glBindTexture(GL_TEXTURE_2D , _texid);
		::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	  }
	  list<int>::iterator ite = _targets.begin();
	  while( ite != _targets.end() ){
		body->_cluster[*ite]->draw(body, draw_state);
		ite++;
	  }
	  if( _texid != 0xFFFFFFFF && draw_state == 0){
		::glDisable(GL_TEXTURE_2D);
		::glDisable(GL_BLEND);
	  }
	}
	break;
  case Group::POLYGON:
	{
	  ::glPolygonOffset( 0.5, 0.5 );
	  ::glColor3fv(_color.color);
	  list<int>::iterator ite = _targets.begin();
	  while( ite != _targets.end() ){
		body->_face[*ite].draw();
		ite++;
	  }
	}
	break;
  case Group::VERTEX:
	{
	  ::glPolygonOffset( 0.5, 0.5 );
	  ::glPointSize( 10.0 );
	  ::glColor3fv(_color.color);
	  list<int>::iterator ite = _targets.begin();
	  ::glBegin(GL_POINTS);
	  while( ite != _targets.end() ){
		::glArrayElement(*ite);
		ite++;
	  }
	  ::glEnd();
	}
	break;
  }
}


//=============================================================================
//	Cluster's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::Cluster::Cluster(const int type, const int sum) :
  _type(type),
  _sum(sum)
{
  if( sum > 0 ){
	_polygon_id = new int[sum];
  }else{
	_polygon_id=NULL;
  }
}

/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::Cluster::~Cluster()
{
  if( _polygon_id!= NULL ) delete [] _polygon_id;
}

/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
void library::graphics::Cluster::set_polygon_id(const int index, int arg)
{
  if( index >= _sum ) return;
  _polygon_id[index]=arg;
}

//=============================================================================
//	TriangleCluster's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::TriangleCluster::TriangleCluster(const int sum) :
  library::graphics::Cluster(Cluster::TRIANGLE_CLUSTER, sum)
{
  if( sum != 0 ){
	_connectivity = new int[sum*3];
	memset(_connectivity, 0, sizeof(int)*sum*3);
	_normal = new Vector3D<double>[sum];
  }else{
	_connectivity = NULL;
	_normal = NULL;
  }
}

/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::TriangleCluster::~TriangleCluster()
{
  if( _connectivity != NULL ) delete [] _connectivity;
  if( _normal != NULL ) delete [] _normal;
}

/**
 * Clients can draw all rectangles belonged to this cluseter using this method.
 * @param draw_state Zero in default.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
int library::graphics::TriangleCluster::draw(PolygonBody* Body,
											 int draw_state)
{
  int sum = _sum;
  ::glBegin(GL_TRIANGLES);
  int* conne = this->_connectivity;
  for( int i = 0; i < sum; i++ ){
	::glNormal3dv(this->_normal[i].vec);
	::glArrayElement(*conne++);
	::glArrayElement(*conne++);
	::glArrayElement(*conne++);
  }
  ::glEnd();
}

/**
 * This method is customized for picking of selection.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
int 
library::graphics::TriangleCluster::selection(library::graphics::PolygonBody* body)
{
  for( int i = 0; i < _sum; i++ ){
	::glLoadName( body->_face[_polygon_id[i]].get_global_id() );
	::glBegin(GL_TRIANGLES);
	::glNormal3dv(this->_normal[i].vec);
	for( int j = 0;j < 3; j++){
	  ::glArrayElement(this->_connectivity[i*3+j]);
	}
	::glEnd();
  }
}

/**
 * Client can get TriangleCluster::_connectivity using this method.
 * @param index Index of triangle.
 * @return The triangle at index, or NULL if index is error number.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
int* library::graphics::TriangleCluster::get_connectivity(const int index)
{
  if( index >= _sum ) return NULL;
  return &(_connectivity[index*3]);
}

/**
 * Client can get _normal using this method.
 * @param index Index of normal of triangle.
 * @return The normal of triangle at index, or NULL if index is error number.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
Vector3D<double>* library::graphics::TriangleCluster::get_normal(int index)
{
  if( index >= _sum ) return NULL;
  return &(_normal[index]);
}

/**
 * Client can set a triangle information using this method.
 * @param body A triangle is belong to this body.
 * @param index Index is the number of triangle in this cluster.
 * @param id Id is the number of triangle in body.
 * @param connectivity Connectivity is a order of Triangle.
 * @retval false Error occurs.
 * @retval true Success.bool
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
bool
library::graphics::TriangleCluster::setPolygon(PolygonBody* body, 
											   const int index, 
											   const int id,
											   const int *connectivity)
{
  if( index >= _sum ) return false;
  _connectivity[index*3+0] = connectivity[0];
  _connectivity[index*3+1] = connectivity[1];
  _connectivity[index*3+2] = connectivity[2];
  _polygon_id[index]=id;
  Vector<double> orign = body->_vertex[_connectivity[index*3]];
  Vector<double> a = body->_vertex[_connectivity[index*3+1]] - orign;
  Vector<double> b = body->_vertex[_connectivity[index*3+2]] - orign;
  Vector<double> outer = a.outerProduct(b);
  outer.normalizing();
  _normal[index]=outer;
  return true;
}

//=============================================================================
//	RectangleCluster's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::RectangleCluster::RectangleCluster(const int sum) :
  library::graphics::Cluster(Cluster::RECTANGLE_CLUSTER, sum)
{
  if( sum != 0 ){
	_connectivity = new int[sum*4];
	_normal = new Vector3D<double>[sum];
  }else{
	_connectivity = NULL;
	_normal = NULL;
  }
}

/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::RectangleCluster::~RectangleCluster()
{
  if( _connectivity != NULL ) delete [] _connectivity;
  if( _normal != NULL ) delete [] _normal;
}

/**
 * Client can set a rectangle information using this method.
 * @param body A rectangle is belong to this body.
 * @param index Index is the number of rectangle in this cluster.
 * @param id Id is the number of rectangle in body.
 * @param connectivity Connectivity is a order of rectangle.
 * @retval false Error occurs.
 * @retval true Success.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
bool 
library::graphics::RectangleCluster::setPolygon(PolygonBody* body, 
												const int index, 
												const int id,
												const int *connectivity)
{
  if( index >= _sum ) return false;
  _connectivity[index*4+0] = connectivity[0];
  _connectivity[index*4+1] = connectivity[1];
  _connectivity[index*4+2] = connectivity[2];
  _connectivity[index*4+3] = connectivity[3];
  _polygon_id[index]=id;
  Vector<double> orign = body->_vertex[_connectivity[index*4]];
  Vector<double> a = body->_vertex[_connectivity[index*4+1]] - orign;
  Vector<double> b = body->_vertex[_connectivity[index*4+2]] - orign;
  Vector<double> outer = a.outerProduct(b);
  outer.normalizing();
  _normal[index]=outer;
  return true;
}

/**
 * Clients can draw all rectangles belonged to this cluseter using this method.
 * @param draw_state Zero in default.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
int library::graphics::RectangleCluster::draw(PolygonBody* Body,
											 int draw_state)
{
  ::glBegin(GL_QUADS);
  for( int i = 0; i < _sum; i++ ){
	::glNormal3dv(this->_normal[i].vec);
	for( int j = 0;j < 4; j++){
	  ::glArrayElement(this->_connectivity[i*4+j]);
	}
  }
  ::glEnd();
}

/**
 * This method is customized for picking of selection.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
int 
library::graphics::RectangleCluster::selection(PolygonBody* body)
{
  for( int i = 0; i < _sum; i++ ){
	::glLoadName( body->_face[_polygon_id[i]].get_global_id() );
	::glBegin(GL_QUADS);
	::glNormal3dv(this->_normal[i].vec);
	for( int j = 0;j < 4; j++){
	  ::glArrayElement(this->_connectivity[i*4+j]);
	}
	::glEnd();
  }
}


/**
 * Client can get RectangleCluster::_connectivity using this method.
 * @param index Index of rectangle.
 * @return The rectangle at index, or NULL if index is error number.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
int* library::graphics::RectangleCluster::get_connectivity(const int index)
{
  if( index >= _sum ) return NULL;
  return &(_connectivity[index*4]);
}


/**
 * Client can get _normal using this method.
 * @param index Index of normal of rectangle.
 * @return The normal of rectangle at index, or NULL if index is error number.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
Vector3D<double>* library::graphics::RectangleCluster::get_normal(int index)
{
  if( index >= _sum ) return NULL;
  return &(_normal[index]);
}

//=============================================================================
//	TriangleStripCluster's method
//=============================================================================
library::graphics::TriangleStripCluster::TriangleStripCluster(const int polsum, 
															  const int sum) :
  library::graphics::Cluster(Cluster::STRIP_CLUSTER, polsum),
  _connectivity_sum(sum)
{
  if( sum != 0 ){
	_connectivity = new int[sum];
	_normal = new Vector3D<double>[polsum];
  }else{
	_connectivity = NULL;
	_normal = NULL;
  }
  _color = Color<float>(rand());
}

library::graphics::TriangleStripCluster::~TriangleStripCluster()
{
  if( _connectivity != NULL ) delete [] _connectivity;
  if( _normal != NULL ) delete [] _normal;
}

/**
 * Clients can draw a triangle strip using this method.
 * @param draw_state Zero in default.
 * @author r-suzuki
 * @date 2008-12-14
 * @version 1.0
 */

int 
library::graphics::TriangleStripCluster::draw(PolygonBody* body,
											  int draw_state)
{
  if( draw_state != 0 ) ::glColor3fv(_color.color);
  ::glBegin(GL_TRIANGLE_STRIP);
  {
	::glNormal3dv( _normal[0].vec);
	::glArrayElement(_connectivity[0]);
	::glArrayElement(_connectivity[1]);
	::glArrayElement(_connectivity[2]);
	for( int i = 3; i < _connectivity_sum; i++){
	  ::glNormal3dv(this->_normal[i-2].vec);
	  ::glArrayElement(_connectivity[i]);
	}
  }
  ::glEnd();
  return 0;
}

/**
 * This method is not still implement.
 * @author r-suzuki
 * @date 2008-12-14
 * @version 1.0
 */
int 
library::graphics::TriangleStripCluster::selection(graphics::PolygonBody* body)
{
  return 0;
}

/**
 * Client can get TriangleStripCluster::_connectivity using this method.
 * @param index Index of triangle.
 * @return The triangle at index, or NULL if index is error number.
 * @author r-suzuki
 * @date 2008-12-14
 * @version 1.0
 */
int* library::graphics::TriangleStripCluster::get_connectivity(const int index)
{
  if( index >= _sum ) return NULL;
  if( index == 0 ) return _connectivity;
  return &(_connectivity[index+2]);
}

/**
 * Client can get TriangleStripCluster::_normal using this method.
 * @param index Index of normal of triangle.
 * @return The normal of triangle at index, or NULL if index is error number.
 * @author r-suzuki
 * @date 2008-12-14
 * @version 1.0
 */
Vector3D<double>* 
library::graphics::TriangleStripCluster::get_normal(int index)
{
  if( index >= _sum ) return NULL;
  return &(_normal[index]);
}

/**
 * Client can set a triangle information using this method.
 * @param body A triangle is belong to this body.
 * @param index Index is the number of triangle in this cluster.
 * @param id Id is the number of triangle in body.
 * @param connectivity Connectivity is a order of Triangle.
 * @retval false Error occurs.
 * @retval true Success.
 * @author r-suzuki
 * @date 2008-12-14
 * @version 1.0
 */
bool
library::graphics::TriangleStripCluster::setPolygon(PolygonBody* body, 
													const int index, 
													const int id,
													const int *connectivity)
{
  if( index >= _sum ) return false;
  if( index == 0 ){
	_connectivity[0] = connectivity[0];
	_connectivity[1] = connectivity[1];
	_connectivity[2] = connectivity[2];
	
  }else{
	_connectivity[index+2] = connectivity[0];
  }

  _normal[index]= *(body->_face[id].get_normal_pointer());
  return true;

}

//=============================================================================
//	PolygonBody's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::PolygonBody::PolygonBody(const int versum ) :
  _vertex_sum(versum)
{
  if( versum != 0 ){
	allocateVertex(versum);
  }else{
	_vertex=NULL;
  }
  _uv = NULL;
  _state = 1;
}

/**
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::PolygonBody::~PolygonBody()
{
  if( _vertex != NULL ) delete [] _vertex;
  if( _uv != NULL ) delete [] _uv;
  vector<library::graphics::Cluster*>::iterator cite = _cluster.begin();
  while( cite != _cluster.end() ){
	delete (*cite);
	cite++;
  }
  _vertex_id.clear();
  _cluster.clear();

  _face.clear();

  vector<library::graphics::Group*>::iterator gite = _groups.begin();
  while( gite != _groups.end() ){
	delete (*gite);
	gite++;
  }
  _groups.clear();
}

/**
 * This method provides to add a cluster.
 * @return If this value is negative, Error occurs.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
int
library::graphics::PolygonBody::appendCluster(library::graphics::Cluster* arg)
{
  int cluster_index;
  int poly_type = 0;
  bool create_poly_flag=true;
  switch( arg->get_type() ){
  case Cluster::TRIANGLE_CLUSTER:
	poly_type=3;
	break;
  case Cluster::RECTANGLE_CLUSTER:
	poly_type=4;
	break;
  case Cluster::STRIP_CLUSTER:
	create_poly_flag=false;
	break;
  default:
	create_poly_flag=false;
	cout << "Can not create with this type "
		 << arg->get_type() << endl;
  }
  cluster_index = _cluster.size();
  _cluster.push_back(arg);
  if( create_poly_flag == true ){
	for( int i = 0; i < arg->get_sum(); i++ ){
	  Polygon face(poly_type, arg->get_connectivity(i), arg->get_normal(i));
	  _face.push_back(face);
	}
  }
  return cluster_index;
}


/**
 * This method provides to add a group.
 * @return If this value is negative, Error occurs.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
void library::graphics::PolygonBody::appendGroup(library::graphics::Group* arg)
{
  if( arg->get_name()[0] == '\0'){
	char tmp[256];
	sprintf(tmp,"group%d",_groups.size());
	arg->set_name(tmp);
  }
  _groups.push_back(arg);
}

/**
 * Client can get a group of index to belong type by this method.
 * @param type 
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-11-17
 */
library::graphics::Group* 
library::graphics::PolygonBody::queryGroup(int type, int target_type, int index)
{
  int counter = 0;
  for( size_t i = 0; i < _groups.size(); i++ ){
	if( _groups[i]->_type == type && _groups[i]->_target_type == target_type ){
	  if( counter == index ){
		return (_groups[i]);
	  }
	  counter++;
	}
  }
  return NULL;
}

/**
 * Client can get a group named client's specifying by this method.
 * @param name Client give a specifying name.
 * @author r-suzuki
 * @date 2008-11-20
 * @version 1.0
 */
Group* library::graphics::PolygonBody::getGroup(const char* name)
{
  for( size_t i = 0; i < _groups.size(); i++ ){
	if( 0 == strcmp(_groups[i]->_name,name) ){
		return (_groups[i]);
	}
  }
  return NULL;
}

/**
 * This work is to give a client a total of specific groups.
 * @return a total of specific groups
 * @author r-suzuki
 * @date 2008-11-19
 * @version 1.0
 */
int 
library::graphics::PolygonBody::querySpecificGroupSum(int type, 
													  int target_type)
{
  int counter = 0;
  for( size_t i = 0; i < _groups.size(); i++ ){
	if( _groups[i]->_type == type ){
	  if( _groups[i]->_target_type == target_type ){
		counter++;
	  }
	}
  }
  return counter;
}

/**
 * This work is to allocate memoery for _uv. When size equal a total of vertex.
 * @author r-suzuki
 * @date 2008-11-18
 * @version 1.0
 */
bool library::graphics::PolygonBody::allocateUV(void)
{
  _uv = new Vector2D<float>[_vertex_sum];
  return true;
}

/**
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
bool library::graphics::PolygonBody::allocateVertex(const int versum)
{
  _vertex_sum= versum;
  _vertex = new Vector<double>[versum];
  _vertex_id.resize(versum);
  return true;

}


/**
 * This method creates simple qubic had eight vertex and six polygon.
 * @author suzuki ryoutoku
 * @date 2008-11-17
 * @version 1.0
 */
library::graphics::PolygonBody* 
library::graphics::PolygonBody::CreateQubicPolygonBody()
{
  PolygonBody* body = new PolygonBody(8);
  body->set_name("QubicPolygonBody");
  body->_vertex[0] = Vector<double>(0.0,0.0,0.0,1.0);
  body->_vertex[1] = Vector<double>(1.0,0.0,0.0,1.0);
  body->_vertex[2] = Vector<double>(1.0,0.0,1.0,1.0);
  body->_vertex[3] = Vector<double>(0.0,0.0,1.0,1.0);
  body->_vertex[4] = Vector<double>(0.0,1.0,0.0,1.0);
  body->_vertex[5] = Vector<double>(1.0,1.0,0.0,1.0);
  body->_vertex[6] = Vector<double>(1.0,1.0,1.0,1.0);
  body->_vertex[7] = Vector<double>(0.0,1.0,1.0,1.0);

  body->allocateUV();

  body->_uv[0] = Vector2D<float>(0.0,0.0);
  body->_uv[1] = Vector2D<float>(1.0,0.0);
  body->_uv[2] = Vector2D<float>(1.0,1.0);
  body->_uv[3] = Vector2D<float>(0.0,1.0);
  body->_uv[4] = Vector2D<float>(0.0,0.0);
  body->_uv[5] = Vector2D<float>(0.5,0.0);
  body->_uv[6] = Vector2D<float>(0.5,0.5);
  body->_uv[7] = Vector2D<float>(0.0,0.5);

  library::graphics::Cluster* cluster = new RectangleCluster(6);
  int order[4];
  order[0] = 2;
  order[1] = 6;
  order[2] = 7;
  order[3] = 3;
  cluster->setPolygon(body,0, 0, order);
  
  order[0] = 0;
  order[1] = 1;
  order[2] = 2;
  order[3] = 3;
  cluster->setPolygon(body,1, 1, order);
  
  order[0] = 7;
  order[1] = 6;
  order[2] = 5;
  order[3] = 4;
  cluster->setPolygon(body,2, 2, order);
  order[0] = 4;
  order[1] = 5;
  order[2] = 1;
  order[3] = 0;
  cluster->setPolygon(body,3, 3, order);

  order[0] = 5;
  order[1] = 6;
  order[2] = 2;
  order[3] = 1;

  cluster->setPolygon(body,4, 4, order);

  order[0] = 7;
  order[1] = 4;
  order[2] = 0;
  order[3] = 3;
  cluster->setPolygon(body,5, 5, order);

  body->appendCluster(cluster);

  // creating a group for selection.
  body->_groups.push_back(new Group(Group::SELECTION, 
									Group::POLYGON, 
									"SelectionPolygon"));
  body->_groups.push_back(new Group(Group::SELECTION, 
									Group::VERTEX,
									"SelectionVertex"));
  
  // creating a group for rectangle cluster
  Group* c_group = new Group( Group::TEXTURE, Group::CLUSTER, "data.jpg");
  c_group->set_name("RectangleClusterGroup");
  c_group->addTarget(0);// cluster is only one.
  body->_groups.push_back(c_group);

  // creating three strip clusters
  cluster = new TriangleStripCluster(8, 10);
  order[0] = 7;
  order[1] = 3;
  order[2] = 6;
  cluster->setPolygon(body,0, 0, order);
  order[0] = 2;
  cluster->setPolygon(body,1, 0, order);
  order[0] = 5;
  cluster->setPolygon(body,2, 4, order);
  order[0] = 1;
  cluster->setPolygon(body,3, 4, order);
  order[0] = 4;
  cluster->setPolygon(body,4, 3, order);
  order[0] = 0;
  cluster->setPolygon(body,5, 3, order);
  order[0] = 7;
  cluster->setPolygon(body,6, 5, order);
  order[0] = 3;
  cluster->setPolygon(body,7, 5, order);
  body->appendCluster(cluster);


  cluster = new TriangleStripCluster(2, 4);
  order[0] = 4;
  order[1] = 7;
  order[2] = 5;
  cluster->setPolygon(body,0, 2, order);
  order[0] = 6;
  cluster->setPolygon(body,1, 2, order);
  body->appendCluster(cluster);

  cluster = new TriangleStripCluster(2, 4);
  order[0] = 1;
  order[1] = 2;
  order[2] = 0;
  cluster->setPolygon(body,0, 1, order);
  order[0] = 3;
  cluster->setPolygon(body,1, 1, order);
  body->appendCluster(cluster);

  // creating a group for strip cluster
  c_group = new Group( Group::TEXTURE, Group::STRIP_CLUSTER, "data.jpg");
  c_group->addTarget(1);
  c_group->addTarget(2);
  c_group->addTarget(3);
  body->_groups.push_back(c_group);

  return body;
}

//=============================================================================
//	Polygon's method
//=============================================================================
/**
 * @param type Client give a type of polygon.
 * @param connectivity Client give a pointer of vertex orderes.
 * @param normal Client give a pointer of normal vector.
 * @author suzuki ryoutoku
 * @date 2008-11-18
 * @version 1.0
 */
library::graphics::Polygon::Polygon(const int type, 
									const int* connectivity, 
									const Vector3D<double>* normal) : 
  _type(type)
{
  _connectivity_pointer=connectivity;
  _normal_pointer=normal;
}

/**
 * @author r-suzuki
 * @version 1.0
 */
library::graphics::Polygon::~Polygon()
{
}

/**
 * This methods draws a polygon.
 * @author r-suzuki
 * @version 1.0
 */
void library::graphics::Polygon::draw(void)
{
  switch(_type){
  case 3:
	::glBegin(GL_TRIANGLES);
	::glNormal3dv(_normal_pointer->vec);
	for( int j = 0;j < 3; j++){
	  ::glArrayElement(_connectivity_pointer[j]);
	}
	::glEnd();
	break;
  case 4:
	::glBegin(GL_QUADS);
	::glNormal3dv(_normal_pointer->vec);
	for( int j = 0;j < 4; j++){
	  ::glArrayElement(_connectivity_pointer[j]);
	}
	::glEnd();
	break;
  }
}

//=============================================================================
//	Define function
//=============================================================================
/**
 * This function creates bitmap file information and bitdata.
 * @param filename Client give filename of bitmap file.
 * @param info This function set bitmap information this parameter.
 * @param pixel This function set bitpattern(bitdata) at this parameter.
 *
 * @retval false Errors occurred.
 * @retval true Success.
 *
 * @author r-suzuki
 * @version 1.0
 */
bool library::graphics::SaveBitmapFile(const string& filename, 
									   BITMAPINFO* info, 
									   unsigned int *pixel)
{
  FILE* fp;
  
  fp = fopen( filename.c_str() , "wb" );
  if( fp == NULL ) return false;
  
  char bfType[2] = { 'B', 'M' };
  DWORD bfSize = 14 + sizeof(BITMAPINFO)*(info->bmiHeader.biHeight*info->bmiHeader.biWidth*sizeof(unsigned int));
  WORD bfReserved1 = 0;
  WORD bfReserved2 = 0;
  DWORD bfOffBits 
	= 14 + sizeof( BITMAPINFO );// This is offset from bitmapinfo to pixel data
  
  fwrite( bfType, sizeof(char), 2, fp);
  fwrite( &bfSize, sizeof(DWORD), 1, fp);
  fwrite( &bfReserved1, sizeof(WORD), 1, fp);
  fwrite( &bfReserved2, sizeof(WORD), 1, fp);
  fwrite( &bfOffBits, sizeof(DWORD), 1, fp);
  
  fwrite( info, sizeof( BITMAPINFO ) , 1, fp);
  fwrite( pixel, 
		  sizeof( unsigned int ), 
		  info->bmiHeader.biHeight * info->bmiHeader.biWidth, fp);
  
  fclose(fp);
  return true;
}


